home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / src / binutils.252 / gas / gasp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-28  |  76.4 KB  |  3,956 lines

  1. /* gasp.c - Gnu assembler preprocessor main program.
  2.    Copyright (C) 1994 Free Software Foundation, Inc.
  3.  
  4.    Written by Steve and Judy Chamberlain of Cygnus Support,
  5.       sac@cygnus.com
  6.  
  7.    This file is part of GASP, the GNU Assembler Preprocessor.
  8.  
  9.    GASP is free software; you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation; either version 2, or (at your option)
  12.    any later version.
  13.  
  14.    GASP is distributed in the hope that it will be useful,
  15.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License
  20.    along with GASP; see the file COPYING.  If not, write to
  21.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  22.  
  23. /*
  24.  
  25. This program translates the input macros and stuff into a form
  26. suitable for gas to consume.
  27.  
  28.  
  29.   gasp [-sdhau] [-c char] [-o <outfile>] <infile>*
  30.  
  31.   -s copy source to output
  32.   -c <char> comments are started with <char> instead of !
  33.   -u allow unreasonable stuff
  34.   -p print line numbers
  35.   -d print debugging stats
  36.   -s semi colons start comments
  37.   -a use alternate syntax
  38.      Pseudo ops can start with or without a .
  39.      Labels have to be in first column.
  40.     Macro arg parameters subsituted by name, don't need the &.
  41.      String can start with ' too.
  42.      Strings can be surrounded by <..>
  43.      A %<exp> in a string evaluates the expression 
  44.      Literal char in a string with !
  45.  
  46.  
  47. */
  48.  
  49.  
  50. #include <stdio.h>
  51. #include <getopt.h>
  52. #include <ctype.h>
  53. #include "config.h"
  54.  
  55. #ifdef HAVE_STDLIB_H
  56. #include <stdlib.h>
  57. #endif
  58.  
  59. #ifdef NEED_MALLOC_DECLARATION
  60. extern char *malloc ();
  61. #endif
  62.  
  63. #include "libiberty.h"
  64.  
  65. char *program_version = "1.2";
  66.  
  67. #define MAX_INCLUDES 30        /* Maximum include depth */
  68. #define MAX_REASONABLE 1000    /* Maximum number of expansions */
  69.  
  70. int unreasonable;        /* -u on command line */
  71. int stats;            /* -d on command line */
  72. int print_line_number;        /* -p flag on command line */
  73. int copysource;            /* -c flag on command line */
  74. int warnings;            /* Number of WARNINGs generated so far. */
  75. int errors;            /* Number of ERRORs generated so far. */
  76. int fatals;            /* Number of fatal ERRORs generated so far (either 0 or 1). */
  77. int alternate = 0;              /* -a on command line */
  78. char comment_char = '!';
  79. int radix = 10;            /* Default radix */
  80.  
  81. int had_end; /* Seen .END */
  82.  
  83. /* The output stream */
  84. FILE *outfile;
  85.  
  86.  
  87. /* Forward declarations. */
  88. static int condass_lookup_name();
  89. static int condass_on();
  90. static int get();
  91. static int get_and_process();
  92. static int get_token();
  93. static int getstring();
  94. static int include_next_index();
  95. static int macro_op();
  96. static int linecount();
  97. static int process_pseudo_op();
  98. static void include_pop();
  99. static void include_print_where_line();
  100. /* string blocks
  101.  
  102.    I had a couple of choices when deciding upon this data structure.
  103.    gas uses null terminated strings for all its internal work.  This
  104.    often means that parts of the program that want to examine
  105.    substrings have to manipulate the data in the string to do the
  106.    right thing (a common operation is to single out a bit of text by
  107.    saving away the character after it, nulling it out, operating on
  108.    the substring and then replacing the character which was under the
  109.    null).  This is a pain and I remember a load of problems that I had with
  110.    code in gas which almost got this right.  Also, it's harder to grow and
  111.    allocate null terminated strings efficiently.
  112.  
  113.    Obstacks provide all the functionality needed, but are too
  114.    complicated, hence the sb.
  115.  
  116.    An sb is allocated by the caller, and is initialzed to point to an
  117.    sb_element.  sb_elements are kept on a free lists, and used when
  118.    needed, replaced onto the free list when unused.
  119.  */
  120.  
  121. #define max_power_two    30    /* don't allow strings more than
  122.                        2^max_power_two long */
  123. /* structure of an sb */
  124. typedef struct sb
  125.   {
  126.     char *ptr;            /* points to the current block. */
  127.     int len;            /* how much is used. */
  128.     int pot;            /* the maximum length is 1<<pot */
  129.     struct le *item;
  130.   }
  131. sb;
  132.  
  133. /* Structure of the free list object of an sb */
  134. typedef struct le
  135.   {
  136.     struct le *next;
  137.     int size;
  138.     char data[1];
  139.   }
  140. sb_element;
  141.  
  142. /* The free list */
  143. typedef struct
  144.   {
  145.     sb_element *size[max_power_two];
  146.   } sb_list_vector;
  147.  
  148. sb_list_vector free_list;
  149.  
  150. int string_count[max_power_two];
  151.  
  152. /* the attributes of each character are stored as a bit pattern
  153.    chartype, which gives us quick tests. */
  154.  
  155.  
  156. #define FIRSTBIT 1
  157. #define NEXTBIT  2
  158. #define SEPBIT   4
  159. #define WHITEBIT 8
  160. #define COMMENTBIT 16
  161. #define BASEBIT  32
  162. #define ISCOMMENTCHAR(x) (chartype[(unsigned)(x)] & COMMENTBIT)
  163. #define ISFIRSTCHAR(x)  (chartype[(unsigned)(x)] & FIRSTBIT)
  164. #define ISNEXTCHAR(x)   (chartype[(unsigned)(x)] & NEXTBIT)
  165. #define ISSEP(x)        (chartype[(unsigned)(x)] & SEPBIT)
  166. #define ISWHITE(x)      (chartype[(unsigned)(x)] & WHITEBIT)
  167. #define ISBASE(x)       (chartype[(unsigned)(x)] & BASEBIT)
  168. static char chartype[256];
  169.  
  170.  
  171. /* Conditional assembly uses the `ifstack'.  Each aif pushes another
  172.    entry onto the stack, and sets the on flag if it should.  The aelse
  173.    sets hadelse, and toggles on.  An aend pops a level.  We limit to
  174.    100 levels of nesting, not because we're facists pigs with read
  175.    only minds, but because more than 100 levels of nesting is probably
  176.    a bug in the user's macro structure.  */
  177.  
  178. #define IFNESTING 100
  179. struct
  180.   {
  181.     int on;            /* is the level being output */
  182.     int hadelse;        /* has an aelse been seen */
  183.   }
  184. ifstack[IFNESTING];
  185. int ifi;
  186.  
  187. /* The final and intermediate results of expression evaluation are kept in
  188.    exp_t's.  Note that a symbol is not an sb, but a pointer into the input
  189.    line.  It must be coped somewhere safe before the next line is read in. */
  190.  
  191. typedef struct
  192.   {
  193.     char *name;
  194.     int len;
  195.   }
  196. symbol;
  197.  
  198. typedef struct
  199.   {
  200.     int value;            /* constant part */
  201.     symbol add_symbol;        /* name part */
  202.     symbol sub_symbol;        /* name part */
  203.   }
  204. exp_t;
  205.  
  206.  
  207. /* Hashing is done in a pretty standard way.  A hash_table has a
  208.    pointer to a vector of pointers to hash_entrys, and the size of the
  209.    vector.  A hash_entry contains a union of all the info we like to
  210.    store in hash table.  If there is a hash collision, hash_entries
  211.    with the same hash are kept in a chain. */
  212.  
  213. /* What the data in a hash_entry means */
  214. typedef enum
  215.   {
  216.     hash_integer,        /* name->integer mapping */
  217.     hash_string,        /* name->string mapping */
  218.     hash_macro,            /* name is a macro */
  219.     hash_formal            /* name is a formal argument */
  220.   } hash_type;
  221.  
  222. typedef struct hs
  223.   {
  224.     sb key;            /* symbol name */
  225.     hash_type type;        /* symbol meaning */
  226.     union
  227.       {
  228.     sb s;
  229.     int i;
  230.     struct macro_struct *m;
  231.     struct formal_struct *f;
  232.       } value;
  233.     struct hs *next;        /* next hash_entry with same hash key */
  234.   } hash_entry;
  235.  
  236. typedef struct
  237.   {
  238.     hash_entry **table;
  239.     int size;
  240.   } hash_table;
  241.  
  242.  
  243. /* Structures used to store macros. 
  244.  
  245.    Each macro knows its name and included text.  It gets built with a
  246.    list of formal arguments, and also keeps a hash table which points
  247.    into the list to speed up formal search.  Each formal knows its
  248.    name and its default value.  Each time the macro is expanded, the
  249.    formals get the actual values attatched to them. */
  250.  
  251. /* describe the formal arguments to a macro */
  252.  
  253. typedef struct formal_struct
  254.   {
  255.     struct formal_struct *next;    /* next formal in list */
  256.     sb name;            /* name of the formal */
  257.     sb def;            /* the default value */
  258.     sb actual;            /* the actual argument (changed on each expansion) */
  259.     int index;            /* the index of the formal 0..formal_count-1 */
  260.   }
  261. formal_entry;
  262.  
  263. /* describe the macro. */
  264.  
  265. typedef struct macro_struct
  266.   {
  267.     sb sub;            /* substitution text. */
  268.     int formal_count;        /* number of formal args. */
  269.     formal_entry *formals;    /* pointer to list of formal_structs */
  270.     hash_table formal_hash;    /* hash table of formals. */
  271.   }
  272. macro_entry;
  273.  
  274. /* how we nest files and expand macros etc.
  275.  
  276.    we keep a stack of of include_stack structs.  each include file
  277.    pushes a new level onto the stack.  we keep an sb with a pushback
  278.    too.  unget chars are pushed onto the pushback sb, getchars first
  279.    checks the pushback sb before reading from the input stream.
  280.  
  281.    small things are expanded by adding the text of the item onto the
  282.    pushback sb.  larger items are grown by pushing a new level and
  283.    allocating the entire pushback buf for the item.  each time
  284.    something like a macro is expanded, the stack index is changed. we
  285.    can then perform an exitm by popping all entries off the stack with
  286.    the same stack index.  if we're being reasonable, we can detect
  287.    recusive expansion by checking the index is reasonably small.
  288.  */
  289.  
  290. typedef enum
  291.   {
  292.     include_file, include_repeat, include_while, include_macro
  293.   } include_type;
  294.  
  295. struct include_stack
  296.   {
  297.     sb pushback;        /* current pushback stream */
  298.     int pushback_index;        /* next char to read from stream */
  299.     FILE *handle;        /* open file */
  300.     sb name;            /* name of file */
  301.     int linecount;        /* number of lines read so far */
  302.     include_type type;
  303.     int index;            /* index of this layer */
  304.   }
  305. include_stack[MAX_INCLUDES];
  306.  
  307. struct include_stack *sp;
  308. #define isp (sp - include_stack)
  309.  
  310. #define dsize 5
  311.  
  312.  
  313. void include_print_where_line ();
  314.  
  315.  
  316. #define FATAL(x) \
  317.   do { include_print_where_line (stderr); fprintf x ; fatals++; quit(); } while(0) 
  318. #define ERROR(x) \
  319.   do { include_print_where_line (stderr); fprintf x; errors++; } while(0)
  320. #define WARNING(x) \
  321.   do { include_print_where_line (stderr); fprintf x; warnings++;} while(0) 
  322.  
  323.  
  324.  
  325. /* exit the program and return the right ERROR code. */
  326. void
  327. quit ()
  328. {
  329.   int exitcode;
  330.   if (fatals + errors)
  331.     exitcode = 1;
  332.   else
  333.     exitcode = 0;
  334.  
  335.   if (stats) 
  336.     {
  337.       int i;
  338.       for (i = 0; i < max_power_two; i++) 
  339.     {
  340.       fprintf (stderr, "strings size %8d : %d\n", 1<<i, string_count[i]);
  341.     }
  342.     }
  343.   exit (exitcode);
  344. }
  345.  
  346.  
  347. /* this program is about manipulating strings.
  348.    they are managed in things called `sb's which is an abbreviation
  349.    for string buffers.  an sb has to be created, things can be glued
  350.    on to it, and at the end of it's life it should be freed.  the
  351.    contents should never be pointed at whilst it is still growing,
  352.    since it could be moved at any time
  353.  
  354.    eg:
  355.    sb_new (&foo);
  356.    sb_grow... (&foo,...);
  357.    use foo->ptr[*];
  358.    sb_kill (&foo);
  359.  
  360. */
  361.  
  362. /* initializes an sb. */
  363.  
  364. void
  365. sb_build (ptr, size)
  366.      sb *ptr;
  367.      int size;
  368. {
  369.   /* see if we can find one to allocate */
  370.   sb_element *e;
  371.  
  372.   if (size > max_power_two)
  373.     {
  374.       FATAL ((stderr, "string longer than %d bytes requested.\n",
  375.           1 << max_power_two));
  376.     }
  377.   e = free_list.size[size];
  378.   if (!e)
  379.     {
  380.       /* nothing there, allocate one and stick into the free list */
  381.       e = (sb_element *) xmalloc (sizeof (sb_element) + (1 << size));
  382.       e->next = free_list.size[size];
  383.       e->size = 1 << size;
  384.       free_list.size[size] = e;
  385.       string_count[size]++;
  386.     }
  387.  
  388.   /* remove from free list */
  389.  
  390.   free_list.size[size] = e->next;
  391.  
  392.   /* copy into callers world */
  393.   ptr->ptr = e->data;
  394.   ptr->pot = size;
  395.   ptr->len = 0;
  396.   ptr->item = e;
  397. }
  398.  
  399.  
  400. static void
  401. sb_new (ptr)
  402.      sb *ptr;
  403. {
  404.   sb_build (ptr, dsize);
  405. }
  406.  
  407. /* deallocate the sb at ptr */
  408.  
  409. static
  410. void
  411. sb_kill (ptr)
  412.      sb *ptr;
  413. {
  414.   /* return item to free list */
  415.   ptr->item->next = free_list.size[ptr->pot];
  416.   free_list.size[ptr->pot] = ptr->item;
  417. }
  418.  
  419. /* add the sb at s to the end of the sb at ptr */
  420.  
  421. static void sb_check ();
  422.  
  423. static
  424. void
  425. sb_add_sb (ptr, s)
  426.      sb *ptr;
  427.      sb *s;
  428. {
  429.   sb_check (ptr, s->len);
  430.   memcpy (ptr->ptr + ptr->len, s->ptr, s->len);
  431.   ptr->len += s->len;
  432. }
  433.  
  434. /* make sure that the sb at ptr has room for another len characters,
  435.    and grow it if it doesn't. */
  436.  
  437. static void
  438. sb_check (ptr, len)
  439.      sb *ptr;
  440.      int len;
  441. {
  442.   if (ptr->len + len >= 1 << ptr->pot)
  443.     {
  444.       sb tmp;
  445.       int pot = ptr->pot;
  446.       while (ptr->len + len >= 1 << pot)
  447.     pot++;
  448.       sb_build (&tmp, pot);
  449.       sb_add_sb (&tmp, ptr);
  450.       sb_kill (ptr);
  451.       *ptr = tmp;
  452.     }
  453. }
  454.  
  455. /* make the sb at ptr point back to the beginning.  */
  456.  
  457. static void
  458. sb_reset (ptr)
  459.      sb *ptr;
  460. {
  461.   ptr->len = 0;
  462. }
  463.  
  464. /* add character c to the end of the sb at ptr. */
  465.  
  466. void
  467. sb_add_char (ptr, c)
  468.      sb *ptr;
  469.      char c;
  470. {
  471.   sb_check (ptr, 1);
  472.   ptr->ptr[ptr->len++] = c;
  473. }
  474.  
  475. /* add null terminated string s to the end of sb at ptr. */
  476.  
  477. static void
  478. sb_add_string (ptr, s)
  479.      sb *ptr;
  480.      char *s;
  481. {
  482.   int len = strlen (s);
  483.   sb_check (ptr, len);
  484.   memcpy (ptr->ptr + ptr->len, s, len);
  485.   ptr->len += len;
  486. }
  487.  
  488. /* add string at s of length len to sb at ptr */
  489.  
  490. static void
  491. sb_add_buffer (ptr, s, len)
  492.      sb *ptr;
  493.      char *s;
  494.      int len;
  495. {
  496.   sb_check (ptr, len);
  497.   memcpy (ptr->ptr + ptr->len, s, len);
  498.   ptr->len += len;
  499. }
  500.  
  501.  
  502. /* print the sb at ptr to the output file */
  503.  
  504. static
  505. void
  506. sb_print (ptr)
  507.      sb *ptr;
  508. {
  509.   int i;
  510.   int nc = 0;
  511.  
  512.   for (i = 0; i < ptr->len; i++)
  513.     {
  514.       if (nc)
  515.     {
  516.       fprintf (outfile, ",");
  517.     }
  518.       fprintf (outfile, "%d", ptr->ptr[i]);
  519.       nc = 1;
  520.     }
  521. }
  522.  
  523. static 
  524. void 
  525. sb_print_at (idx, ptr)
  526. int idx;
  527. sb *ptr;
  528. {
  529.   int i;
  530.   for (i = idx; i < ptr->len; i++)
  531.     putc (ptr->ptr[i], outfile);
  532. }
  533. /* put a null at the end of the sb at in and return the start of the
  534.    string, so that it can be used as an arg to printf %s. */
  535.  
  536. static
  537. char *
  538. sb_name (in)
  539.      sb *in;
  540. {
  541.   /* stick a null on the end of the string */
  542.   sb_add_char (in, 0);
  543.   return in->ptr;
  544. }
  545.  
  546. /* start at the index idx into the string in sb at ptr and skip
  547.    whitespace. return the index of the first non whitespace character */
  548.  
  549. static int
  550. sb_skip_white (idx, ptr)
  551.      int idx;
  552.      sb *ptr;
  553. {
  554.   while (idx < ptr->len && ISWHITE (ptr->ptr[idx]))
  555.     idx++;
  556.   return idx;
  557. }
  558.  
  559. /* start at the index idx into the sb at ptr. skips whitespace,
  560.    a comma and any following whitespace. returnes the index of the
  561.    next character. */
  562.  
  563. static int
  564. sb_skip_comma (idx, ptr)
  565.      int idx;
  566.      sb *ptr;
  567. {
  568.   while (idx < ptr->len && ISWHITE (ptr->ptr[idx]))
  569.     idx++;
  570.  
  571.   if (idx < ptr->len
  572.       && ptr->ptr[idx] == ',')
  573.     idx++;
  574.  
  575.   while (idx < ptr->len && ISWHITE (ptr->ptr[idx]))
  576.     idx++;
  577.  
  578.   return idx;
  579. }
  580.  
  581.  
  582. /* hash table maintenance. */
  583.  
  584. /* build a new hash table with size buckets, and fill in the info at ptr. */
  585.  
  586. static void
  587. hash_new_table (size, ptr)
  588.      int size;
  589.      hash_table *ptr;
  590. {
  591.   int i;
  592.   ptr->size = size;
  593.   ptr->table = (hash_entry **) xmalloc (size * (sizeof (hash_entry *)));
  594.   /* Fill with null-pointer, not zero-bit-pattern.  */
  595.   for (i = 0; i < size; i++)
  596.     ptr->table[i] = 0;
  597. }
  598.  
  599. /* calculate and return the hash value of the sb at key. */
  600.  
  601. static int
  602. hash (key)
  603.      sb *key;
  604. {
  605.   int k = 0x1234;
  606.   int i;
  607.   char *p = key->ptr;
  608.   for (i = 0; i < key->len; i++)
  609.     {
  610.       k ^= (k << 2) ^ *p;
  611.       p++;
  612.     }
  613.   return k & 0xf0fff;
  614. }
  615.  
  616. /* lookup key in hash_table tab, if present, then return it, otherwise
  617.    build a new one and fill it with hash_integer. */
  618.  
  619. static
  620. hash_entry *
  621. hash_create (tab, key)
  622.      hash_table *tab;
  623.      sb *key;
  624. {
  625.   int k = hash (key) % tab->size;
  626.   hash_entry *p;
  627.   hash_entry **table = tab->table;
  628.  
  629.   p = table[k];
  630.  
  631.   while (1)
  632.     {
  633.       if (!p)
  634.     {
  635.       hash_entry *n = (hash_entry *) xmalloc (sizeof (hash_entry));
  636.       n->next = table[k];
  637.       sb_new (&n->key);
  638.       sb_add_sb (&n->key, key);
  639.       table[k] = n;
  640.       n->type = hash_integer;
  641.       return n;
  642.     }
  643.       if (strncmp (table[k]->key.ptr, key->ptr, key->len) == 0)
  644.     {
  645.       return p;
  646.     }
  647.       p = p->next;
  648.     }
  649. }
  650.  
  651. /* add sb name with key into hash_table tab.  if replacing old value
  652.    and again, then ERROR. */
  653.  
  654. static
  655. void
  656. hash_add_to_string_table (tab, key, name, again)
  657.      hash_table *tab;
  658.      sb *key;
  659.      sb *name;
  660.      int again;
  661. {
  662.   hash_entry *ptr = hash_create (tab, key);
  663.   if (ptr->type == hash_integer)
  664.     {
  665.       sb_new (&ptr->value.s);
  666.     }
  667.   if (ptr->value.s.len)
  668.     {
  669.       if (!again)
  670.     ERROR ((stderr, "redefintion not allowed"));
  671.     }
  672.  
  673.   ptr->type = hash_string;
  674.   sb_reset (&ptr->value.s);
  675.   
  676.   sb_add_sb (&ptr->value.s, name);
  677. }
  678.  
  679. /* add integer name to hash_table tab with sb key. */
  680.  
  681. static
  682. void
  683. hash_add_to_int_table (tab, key, name)
  684.      hash_table *tab;
  685.      sb *key;
  686.      int name;
  687. {
  688.   hash_entry *ptr = hash_create (tab, key);
  689.   ptr->value.i = name;
  690. }
  691.  
  692. /* lookup sb key in hash_table tab.  if found return hash_entry result,
  693.    else 0. */
  694.    
  695. static
  696. hash_entry *
  697. hash_lookup (tab, key)
  698.      hash_table *tab;
  699.      sb *key;
  700. {
  701.   int k = hash (key) % tab->size;
  702.   hash_entry **table = tab->table;
  703.   hash_entry *p = table[k];
  704.   while (p)
  705.     {
  706.       if (p->key.len == key->len
  707.       && strncmp (p->key.ptr, key->ptr, key->len) == 0)
  708.     return p;
  709.       p = p->next;
  710.     }
  711.   return 0;
  712. }
  713.  
  714.  
  715. /* expressions
  716.  
  717.    are handled in a really simple recursive decent way. each bit of
  718.    the machine takes an index into an sb and a pointer to an exp_t,
  719.    modifies the *exp_t and returns the index of the first character
  720.    past the part of the expression parsed.
  721.  
  722.  expression precedence:
  723.   ( )
  724.  unary + - ~
  725.   * /
  726.   + -
  727.   &
  728.   | ~
  729.  
  730. */
  731.  
  732.  
  733. /* make sure that the exp_t at term is constant, if not the give the op ERROR. */
  734.  
  735. static
  736. void
  737. checkconst (op, term)
  738.      char op;
  739.      exp_t *term;
  740. {
  741.   if (term->add_symbol.len
  742.       || term->sub_symbol.len)
  743.     {
  744.       ERROR ((stderr, "the %c operator cannot take non-absolute arguments.\n", op));
  745.     }
  746. }
  747.  
  748. /* turn the number in string at idx into a number of base,
  749.    fill in ptr and return the index of the first character not in the
  750.    number. */
  751.  
  752. static
  753. int
  754. sb_strtol (idx, string, base, ptr)
  755.      int idx;
  756.      sb *string;
  757.      int base;
  758.      int *ptr;
  759. {
  760.   int value = 0;
  761.   idx = sb_skip_white (idx, string);
  762.  
  763.   while (idx < string->len)
  764.     {
  765.       int ch = string->ptr[idx];
  766.       int dig = 0;
  767.       if (isdigit (ch))
  768.     dig = ch - '0';
  769.       else if (ch >= 'a' && ch <= 'f')
  770.     dig = ch - 'a' + 10;
  771.       else if (ch >= 'A' && ch <= 'F')
  772.     dig = ch - 'A' + 10;
  773.       else
  774.     break;
  775.  
  776.       if (dig >= base)
  777.     break;
  778.  
  779.       value = value * base + dig;
  780.       idx++;
  781.     }
  782.   *ptr = value;
  783.   return idx;
  784. }
  785.  
  786. static int level_5 ();
  787.  
  788. int
  789. level_0 (idx, string, lhs)
  790.      int idx;
  791.      sb *string;
  792.      exp_t *lhs;
  793. {
  794.   lhs->add_symbol.len = 0;
  795.   lhs->add_symbol.name = 0;
  796.  
  797.   lhs->sub_symbol.len = 0;
  798.   lhs->sub_symbol.name = 0;
  799.  
  800.   idx = sb_skip_white (idx, string);
  801.  
  802.   lhs->value = 0;
  803.  
  804.   if (isdigit (string->ptr[idx]))
  805.     {
  806.       idx = sb_strtol (idx, string, 10, &lhs->value);
  807.     }
  808.   else if (ISFIRSTCHAR (string->ptr[idx]))
  809.     {
  810.       int len = 0;
  811.       lhs->add_symbol.name = string->ptr + idx;
  812.       while (idx < string->len && ISNEXTCHAR (string->ptr[idx]))
  813.     {
  814.       idx++;
  815.       len++;
  816.     }
  817.       lhs->add_symbol.len = len;
  818.     }
  819.   else if (string->ptr[idx] == '"')
  820.     {
  821.       sb acc;
  822.       sb_new (&acc);
  823.       ERROR ((stderr, "string where expression expected.\n"));
  824.       idx = getstring (idx, string, &acc);
  825.       sb_kill (&acc);
  826.     }
  827.   else
  828.     {
  829.       ERROR ((stderr, "can't find primary in expression.\n"));
  830.       idx++;
  831.     }
  832.   return sb_skip_white (idx, string);
  833. }
  834.  
  835.  
  836.  
  837. static int
  838. level_1 (idx, string, lhs)
  839.      int idx;
  840.      sb *string;
  841.      exp_t *lhs;
  842. {
  843.   idx = sb_skip_white (idx, string);
  844.  
  845.   switch (string->ptr[idx])
  846.     {
  847.     case '+':
  848.       idx = level_1 (idx + 1, string, lhs);
  849.       break;
  850.     case '~':
  851.       idx = level_1 (idx + 1, string, lhs);
  852.       checkconst ('~', lhs);
  853.       lhs->value = ~lhs->value;
  854.       break;
  855.     case '-':
  856.       {
  857.     symbol t;
  858.     idx = level_1 (idx + 1, string, lhs);
  859.     lhs->value = -lhs->value;
  860.     t = lhs->add_symbol;
  861.     lhs->add_symbol = lhs->sub_symbol;
  862.     lhs->sub_symbol = t;
  863.     break;
  864.       }
  865.     case '(':
  866.       idx++;
  867.       idx = level_5 (sb_skip_white (idx, string), string, lhs);
  868.       if (string->ptr[idx] != ')')
  869.     ERROR ((stderr, "misplaced closing parens.\n"));
  870.       else
  871.     idx++;
  872.       break;
  873.     default:
  874.       idx = level_0 (idx, string, lhs);
  875.       break;
  876.     }
  877.   return sb_skip_white (idx, string);
  878. }
  879.  
  880. static int
  881. level_2 (idx, string, lhs)
  882.      int idx;
  883.      sb *string;
  884.      exp_t *lhs;
  885. {
  886.   exp_t rhs;
  887.  
  888.   idx = level_1 (idx, string, lhs);
  889.  
  890.   while (idx < string->len && (string->ptr[idx] == '*'
  891.                    || string->ptr[idx] == '/'))
  892.     {
  893.       char op = string->ptr[idx++];
  894.       idx = level_1 (idx, string, &rhs);
  895.       switch (op)
  896.     {
  897.     case '*':
  898.       checkconst ('*', lhs);
  899.       checkconst ('*', &rhs);
  900.       lhs->value *= rhs.value;
  901.       break;
  902.     case '/':
  903.       checkconst ('/', lhs);
  904.       checkconst ('/', &rhs);
  905.       if (rhs.value == 0)
  906.         ERROR ((stderr, "attempt to divide by zero.\n"));
  907.       else
  908.         lhs->value /= rhs.value;
  909.       break;
  910.     }
  911.     }
  912.   return sb_skip_white (idx, string);
  913. }
  914.  
  915.  
  916. static int
  917. level_3 (idx, string, lhs)
  918.      int idx;
  919.      sb *string;
  920.      exp_t *lhs;
  921. {
  922.   exp_t rhs;
  923.  
  924.   idx = level_2 (idx, string, lhs);
  925.  
  926.   while (idx < string->len
  927.      && (string->ptr[idx] == '+'
  928.          || string->ptr[idx] == '-'))
  929.     {
  930.       char op = string->ptr[idx++];
  931.       idx = level_2 (idx, string, &rhs);
  932.       switch (op)
  933.     {
  934.     case '+':
  935.       lhs->value += rhs.value;
  936.       if (lhs->add_symbol.name && rhs.add_symbol.name)
  937.         {
  938.           ERROR ((stderr, "can't add two relocatable expressions\n"));
  939.         }
  940.       /* change nn+symbol to symbol + nn */
  941.       if (rhs.add_symbol.name)
  942.         {
  943.           lhs->add_symbol = rhs.add_symbol;
  944.         }
  945.       break;
  946.     case '-':
  947.       lhs->value -= rhs.value;
  948.       lhs->sub_symbol = rhs.add_symbol;
  949.       break;
  950.     }
  951.     }
  952.   return sb_skip_white (idx, string);
  953. }
  954.  
  955. static int
  956. level_4 (idx, string, lhs)
  957.      int idx;
  958.      sb *string;
  959.      exp_t *lhs;
  960. {
  961.   exp_t rhs;
  962.  
  963.   idx = level_3 (idx, string, lhs);
  964.  
  965.   while (idx < string->len &&
  966.      string->ptr[idx] == '&')
  967.     {
  968.       char op = string->ptr[idx++];
  969.       idx = level_3 (idx, string, &rhs);
  970.       switch (op)
  971.     {
  972.     case '&':
  973.       checkconst ('&', lhs);
  974.       checkconst ('&', &rhs);
  975.       lhs->value &= rhs.value;
  976.       break;
  977.     }
  978.     }
  979.   return sb_skip_white (idx, string);
  980. }
  981.  
  982. static int
  983. level_5 (idx, string, lhs)
  984.      int idx;
  985.      sb *string;
  986.      exp_t *lhs;
  987. {
  988.   exp_t rhs;
  989.  
  990.   idx = level_4 (idx, string, lhs);
  991.  
  992.   while (idx < string->len
  993.      && (string->ptr[idx] == '|' || string->ptr[idx] == '~'))
  994.     {
  995.       char op = string->ptr[idx++];
  996.       idx = level_4 (idx, string, &rhs);
  997.       switch (op)
  998.     {
  999.     case '|':
  1000.       checkconst ('|', lhs);
  1001.       checkconst ('|', &rhs);
  1002.       lhs->value |= rhs.value;
  1003.       break;
  1004.     case '~':
  1005.       checkconst ('~', lhs);
  1006.       checkconst ('~', &rhs);
  1007.       lhs->value ^= rhs.value;
  1008.       break;
  1009.     }
  1010.     }
  1011.   return sb_skip_white (idx, string);
  1012. }
  1013.  
  1014.  
  1015. /* parse the expression at offset idx into string, fill up res with
  1016.    the result. return the index of the first char past the expression.
  1017.    */
  1018.  
  1019. static int
  1020. exp_parse (idx, string, res)
  1021.      int idx;
  1022.      sb *string;
  1023.      exp_t *res;
  1024. {
  1025.   return level_5 (sb_skip_white (idx, string), string, res);
  1026. }
  1027.  
  1028.  
  1029. /* turn the expression at exp into text and glue it onto the end of
  1030.    string. */
  1031.  
  1032. static void
  1033. exp_string (exp, string)
  1034.      exp_t *exp;
  1035.      sb *string;
  1036. {
  1037.   int np = 0;
  1038.   int ad = 0;
  1039.   sb_reset (string);
  1040.  
  1041.   if (exp->add_symbol.len)
  1042.     {
  1043.       sb_add_buffer (string, exp->add_symbol.name, exp->add_symbol.len);
  1044.       np = 1;
  1045.       ad = 1;
  1046.     }
  1047.   if (exp->value)
  1048.     {
  1049.       char buf[20];
  1050.       if (np)
  1051.     sb_add_char (string, '+');
  1052.       sprintf (buf, "%d", exp->value);
  1053.       sb_add_string (string, buf);
  1054.       np = 1;
  1055.       ad = 1;
  1056.     }
  1057.   if (exp->sub_symbol.len)
  1058.     {
  1059.       sb_add_char (string, '-');
  1060.       sb_add_buffer (string, exp->add_symbol.name, exp->add_symbol.len);
  1061.       np = 0;
  1062.       ad = 1;
  1063.     }
  1064.  
  1065.   if (!ad)
  1066.     sb_add_char (string, '0');
  1067. }
  1068.  
  1069.  
  1070. /* parse the expression at offset idx into sb in, return the value in val.  
  1071.    if the expression is not constant, give ERROR emsg.  returns the index
  1072.    of the first character past the end of the expression. */
  1073.  
  1074. static int
  1075. exp_get_abs (emsg, idx, in, val)
  1076.      char *emsg;
  1077.      int idx;
  1078.      sb *in;
  1079.      int *val;
  1080. {
  1081.   exp_t res;
  1082.   idx = exp_parse (idx, in, &res);
  1083.   if (res.add_symbol.len || res.sub_symbol.len)
  1084.     ERROR ((stderr, emsg));
  1085.   *val = res.value;
  1086.   return idx;
  1087. }
  1088.  
  1089.  
  1090. sb label; /* current label parsed from line */
  1091. hash_table assign_hash_table;   /* hash table for all assigned variables */
  1092. hash_table keyword_hash_table;  /* hash table for keyword */
  1093. hash_table vars;  /* hash table for  eq variables */
  1094.  
  1095. #define in_comment ';'
  1096.  
  1097. #if 1
  1098. void
  1099. strip_comments (out)
  1100.      sb *out;
  1101. {
  1102.   char *s = out->ptr;
  1103.   int i = 0;
  1104.   for (i = 0; i < out->len; i++)
  1105.     {
  1106.       if (ISCOMMENTCHAR(s[i]))
  1107.     {
  1108.       out->len = i;
  1109.       return;
  1110.     }
  1111.     }
  1112. }
  1113. #endif
  1114.  
  1115. /* push back character ch so that it can be read again. */
  1116.  
  1117. void
  1118. unget (ch)
  1119.      int ch;
  1120. {
  1121.   if (ch == '\n')
  1122.     {
  1123.       sp->linecount--;
  1124.     }
  1125.   if (sp->pushback_index)
  1126.     sp->pushback_index--;
  1127.   else
  1128.     sb_add_char (&sp->pushback, ch);
  1129. }
  1130.  
  1131. /* push the sb ptr onto the include stack, with the given name, type and index. */
  1132.  
  1133. static
  1134. void
  1135. include_buf (name, ptr, type, index)
  1136.      sb *name;
  1137.      sb *ptr;
  1138.      include_type type;
  1139.      int index;
  1140. {
  1141.   sp++;
  1142.   if (sp - include_stack >= MAX_INCLUDES)
  1143.     FATAL ((stderr, "unreasonable nesting.\n"));
  1144.   sb_new (&sp->name);
  1145.   sb_add_sb (&sp->name, name);
  1146.   sp->handle = 0;
  1147.   sp->linecount = 1;
  1148.   sp->pushback_index = 0;
  1149.   sp->type = type;
  1150.   sp->index = index;
  1151.   sb_new (&sp->pushback);
  1152.   sb_add_sb (&sp->pushback, ptr);
  1153. }
  1154.  
  1155.  
  1156. /* used in ERROR messages, print info on where the include stack is onto file. */
  1157. static 
  1158. void
  1159. include_print_where_line (file)
  1160.      FILE *file;
  1161. {
  1162.   struct include_stack *p = include_stack + 1;
  1163.  
  1164.   while (p <= sp)
  1165.     {
  1166.       fprintf (file, "%s:%d ", sb_name (&p->name), p->linecount - ((p == sp) ? 1 : 0));
  1167.       p++;
  1168.     }
  1169. }
  1170.  
  1171. /* used in listings, print the line number onto file. */
  1172. static void
  1173. include_print_line (file)
  1174.      FILE *file;
  1175. {
  1176.   int n;
  1177.   struct include_stack *p = include_stack + 1;
  1178.  
  1179.   n = fprintf (file, "%4d", p->linecount);
  1180.   p++;
  1181.   while (p <= sp)
  1182.     {
  1183.       n += fprintf (file, ".%d", p->linecount);
  1184.       p++;
  1185.     }
  1186.   while (n < 8 * 3)
  1187.     {
  1188.       fprintf (file, " ");
  1189.       n++;
  1190.     }
  1191. }
  1192.  
  1193.  
  1194. /* read a line from the top of the include stack into sb in. */
  1195.  
  1196. static int
  1197. get_line (in)
  1198.      sb *in;
  1199. {
  1200.   int online = 0;
  1201.   int more = 1;
  1202.  
  1203.   if (copysource)
  1204.     {
  1205.       putc (comment_char, outfile);
  1206.       if (print_line_number)
  1207.     include_print_line (outfile);
  1208.     }
  1209.  
  1210.   while (1)
  1211.     {
  1212.       int ch = get ();
  1213.  
  1214.       while (ch == '\r')
  1215.     ch = get ();
  1216.  
  1217.       if (ch == EOF)
  1218.     {
  1219.       if (online)
  1220.         {
  1221.           WARNING ((stderr, "End of file not at start of line.\n"));
  1222.           if (copysource)
  1223.         putc ('\n', outfile);
  1224.           ch = '\n';
  1225.         }
  1226.       else
  1227.         more = 0;
  1228.       break;
  1229.     }
  1230.  
  1231.       if (copysource)
  1232.     {
  1233.       putc (ch, outfile);
  1234.     }
  1235.  
  1236.       if (ch == '\n')
  1237.     {
  1238.       ch = get ();
  1239.       online = 0;
  1240.       if (ch == '+')
  1241.         {
  1242.           /* continued line */
  1243.           if (copysource)
  1244.         {
  1245.           putc (comment_char, outfile);
  1246.           putc ('+', outfile);
  1247.         }
  1248.           ch = get ();
  1249.         }
  1250.       else
  1251.         {
  1252.           if (ch != EOF)
  1253.         unget (ch);
  1254.           break;
  1255.         }
  1256.     }
  1257.       else
  1258.     {
  1259.       sb_add_char (in, ch);
  1260.     }
  1261.       online++;
  1262.     }
  1263.  
  1264.   return more;
  1265. }
  1266.  
  1267. /* find a label from sb in and put it in out. */
  1268.  
  1269. static int
  1270. grab_label (in, out)
  1271.      sb *in;
  1272.      sb *out;
  1273. {
  1274.   int i = 0;
  1275.   sb_reset (out);
  1276.   if (ISFIRSTCHAR (in->ptr[i]))
  1277.     {
  1278.       sb_add_char (out, in->ptr[i]);
  1279.       i++;
  1280.       while ((ISNEXTCHAR (in->ptr[i]) 
  1281.           || in->ptr[i] == '\\'
  1282.           || in->ptr[i] == '&') 
  1283.          && i < in->len)
  1284.     {
  1285.       sb_add_char (out, in->ptr[i]);
  1286.       i++;
  1287.     }
  1288.     }
  1289.   return i;
  1290. }
  1291.  
  1292. /* find all strange base stuff and turn into decimal. also
  1293.    find all the other numbers and convert them from the default radix */
  1294.  
  1295. static void
  1296. change_base (idx, in, out)
  1297.      int idx;
  1298.      sb *in;
  1299.      sb *out;
  1300. {
  1301.   char buffer[20];
  1302.  
  1303.   while (idx < in->len)
  1304.     {
  1305.       if (idx < in->len - 1 && in->ptr[idx + 1] == '\'')
  1306.     {
  1307.       int base;
  1308.       int value;
  1309.       switch (in->ptr[idx])
  1310.         {
  1311.         case 'b':
  1312.         case 'B':
  1313.           base = 2;
  1314.           break;
  1315.         case 'q':
  1316.         case 'Q':
  1317.           base = 8;
  1318.           break;
  1319.         case 'h':
  1320.         case 'H':
  1321.           base = 16;
  1322.           break;
  1323.         case 'd':
  1324.         case 'D':
  1325.           base = 10;
  1326.           break;
  1327.         default:
  1328.           ERROR ((stderr, "Illegal base character %c.\n", in->ptr[idx]));
  1329.           base = 10;
  1330.           break;
  1331.         }
  1332.  
  1333.       idx = sb_strtol (idx + 2, in, base, &value);
  1334.       sprintf (buffer, "%d", value);
  1335.       sb_add_string (out, buffer);
  1336.     }
  1337.       else if (ISFIRSTCHAR (in->ptr[idx]))
  1338.     {
  1339.       /* copy entire names through quickly */
  1340.       sb_add_char (out, in->ptr[idx]);
  1341.       idx++;
  1342.       while (idx < in->len && ISNEXTCHAR (in->ptr[idx]))
  1343.         {
  1344.           sb_add_char (out, in->ptr[idx]);
  1345.           idx++;
  1346.         }
  1347.     }
  1348.       else if (isdigit (in->ptr[idx]))
  1349.     {
  1350.       int value;
  1351.       /* all numbers must start with a digit, let's chew it and
  1352.          spit out decimal */
  1353.       idx = sb_strtol (idx, in, radix, &value);
  1354.       sprintf (buffer, "%d", value);
  1355.       sb_add_string (out, buffer);
  1356.  
  1357.       /* skip all undigsested letters */
  1358.       while (idx < in->len && ISNEXTCHAR (in->ptr[idx]))
  1359.         {
  1360.           sb_add_char (out, in->ptr[idx]);
  1361.           idx++;
  1362.         }
  1363.     }
  1364.       else
  1365.     {
  1366.       /* nothing special, just pass it through */
  1367.       sb_add_char (out, in->ptr[idx]);
  1368.       idx++;
  1369.     }
  1370.     }
  1371.  
  1372. }
  1373.  
  1374. /* .end */
  1375. static void
  1376. do_end ()
  1377. {
  1378.   had_end = 1;
  1379. }
  1380.  
  1381. /* .assign */
  1382.  
  1383. static void
  1384. do_assign (again, idx, in)
  1385.      int again;
  1386.      int idx;
  1387.      sb *in;
  1388. {
  1389.   /* stick label in symbol table with following value */
  1390.   exp_t e;
  1391.   sb acc;
  1392.  
  1393.   sb_new (&acc);
  1394.   idx = exp_parse (idx, in, &e);
  1395.   exp_string (&e, &acc);
  1396.   hash_add_to_string_table (&assign_hash_table, &label, &acc, again);
  1397.   sb_kill (&acc);
  1398. }
  1399.  
  1400.  
  1401. /* .radix [b|q|d|h] */
  1402.  
  1403. static
  1404. void
  1405. do_radix (ptr)
  1406.      sb *ptr;
  1407. {
  1408.   int idx = sb_skip_white (0, ptr);
  1409.   switch (ptr->ptr[idx])
  1410.     {
  1411.     case 'B':
  1412.     case 'b':
  1413.       radix = 2;
  1414.       break;
  1415.     case 'q':
  1416.     case 'Q':
  1417.       radix = 8;
  1418.       break;
  1419.     case 'd':
  1420.     case 'D':
  1421.       radix = 10;
  1422.       break;
  1423.     case 'h':
  1424.     case 'H':
  1425.       radix = 16;
  1426.       break;
  1427.     default:
  1428.       ERROR ((stderr, "radix is %c must be one of b, q, d or h", radix));
  1429.     }
  1430. }
  1431.  
  1432.  
  1433. /* Parse off a .b, .w or .l */
  1434.  
  1435. static int
  1436. get_opsize (idx, in, size)
  1437. int idx;
  1438. sb *in;
  1439. int *size;
  1440. {
  1441.   *size = 4;
  1442.   if (in->ptr[idx] == '.')
  1443.     {
  1444.       idx++;
  1445.     }
  1446.   switch (in->ptr[idx])
  1447.     {
  1448.     case 'b':
  1449.     case 'B':
  1450.       *size = 1;
  1451.       break;
  1452.     case 'w':
  1453.     case 'W':
  1454.       *size = 2;
  1455.       break;
  1456.     case 'l':
  1457.     case 'L':
  1458.       *size = 4;
  1459.       break;
  1460.     case ' ':
  1461.     case '\t':
  1462.       break;
  1463.     default:
  1464.       ERROR ((stderr, "size must be one of b, w or l, is %c.\n", in->ptr[idx]));
  1465.       break;
  1466.     }
  1467.   idx++;
  1468.  
  1469.   return idx;
  1470. }
  1471.  
  1472. static 
  1473. int eol(idx, line)
  1474. int idx;
  1475. sb *line;
  1476. {
  1477.   idx = sb_skip_white (idx, line);
  1478.   if (idx < line->len 
  1479.       && ISCOMMENTCHAR(line->ptr[idx]))
  1480.     return 1;
  1481.   if (idx >= line->len)
  1482.     return 1;
  1483.   return 0;
  1484. }
  1485.  
  1486. /* .data [.b|.w|.l] <data>* 
  1487.     or d[bwl] <data>* */
  1488.  
  1489. static void
  1490. do_data (idx, in, size)
  1491.      int idx;
  1492.      sb *in;
  1493.      int size;
  1494. {
  1495.   int opsize = 4;
  1496.   char *opname;
  1497.   sb acc;
  1498.   sb_new (&acc);
  1499.  
  1500.   if (!size) 
  1501.     {
  1502.       idx = get_opsize (idx, in, &opsize);
  1503.     }
  1504.   else {
  1505.     opsize = size;
  1506.   }
  1507.   switch (opsize)
  1508.     {
  1509.     case 4:
  1510.       opname = ".long";
  1511.       break;
  1512.     case 2:
  1513.       opname = ".short";
  1514.       break;
  1515.     case 1:
  1516.       opname = ".byte";
  1517.       break;
  1518.     }
  1519.  
  1520.  
  1521.   fprintf (outfile, "%s\t", opname);
  1522.  
  1523.   idx =   sb_skip_white (idx, in);
  1524.  
  1525.   if (alternate 
  1526.       && idx < in->len 
  1527.       && in->ptr[idx] == '"')
  1528.     {
  1529.       int i;
  1530.       idx = getstring (idx, in, &acc);
  1531.       for (i = 0; i < acc.len; i++)
  1532.     {
  1533.       if (i)
  1534.         fprintf(outfile,",");
  1535.       fprintf (outfile, "%d", acc.ptr[i]);
  1536.     }
  1537.     }
  1538.   else 
  1539.     {
  1540.       while (!eol (idx, in))
  1541.     {
  1542.       exp_t e;
  1543.       idx = exp_parse (idx, in, &e);
  1544.       exp_string (&e, &acc);
  1545.       sb_add_char (&acc, 0);
  1546.       fprintf (outfile, acc.ptr);
  1547.       if (idx < in->len && in->ptr[idx] == ',')
  1548.         {
  1549.           fprintf (outfile, ",");
  1550.           idx++;
  1551.         }
  1552.     }
  1553.     }
  1554.   sb_kill (&acc);
  1555.   sb_print_at (idx, in);
  1556.   fprintf (outfile, "\n");
  1557. }
  1558.  
  1559. /* .datab [.b|.w|.l] <repeat>,<fill> */
  1560.  
  1561. static void
  1562. do_datab (idx, in)
  1563.      int idx;
  1564.      sb *in;
  1565. {
  1566.   int opsize;
  1567.   int repeat;
  1568.   int fill;
  1569.  
  1570.   idx = get_opsize (idx, in, &opsize);
  1571.  
  1572.   idx = exp_get_abs ("datab repeat must be constant.\n", idx, in, &repeat);
  1573.   idx = sb_skip_comma (idx, in);
  1574.   idx = exp_get_abs ("datab data must be absolute.\n", idx, in, &fill);
  1575.  
  1576.   fprintf (outfile, ".fill\t%d,%d,%d\n", repeat, opsize, fill);
  1577. }
  1578.  
  1579. /* .align <size> */
  1580.  
  1581. void
  1582. do_align (idx, in)
  1583.      int idx;
  1584.      sb *in;
  1585. {
  1586.   int al;
  1587.   idx = exp_get_abs ("align needs absolute expression.\n", idx, in, &al);
  1588.  
  1589.   if (al != 1
  1590.       && al != 2
  1591.       && al != 4)
  1592.     WARNING ((stderr, "alignment must be one of 1, 2 or 4.\n"));
  1593.  
  1594.   fprintf (outfile, ".align    %d\n", al);
  1595. }
  1596.  
  1597. /* .res[.b|.w|.l] <size> */
  1598.  
  1599. void
  1600. do_res (idx, in, type)
  1601.      int idx;
  1602.      sb *in;
  1603.      char type;
  1604. {
  1605.   int size = 4;
  1606.   int count = 0;
  1607.  
  1608.   idx = get_opsize (idx, in, &size);
  1609.   while (!eol(idx, in))
  1610.     {
  1611.       idx = sb_skip_white (idx, in);
  1612.       if (in->ptr[idx] == ',')
  1613.     idx++;
  1614.       idx = exp_get_abs ("res needs absolute expression for fill count.\n", idx, in, &count);
  1615.  
  1616.       if (type == 'c' || type == 'z')
  1617.     count++;
  1618.  
  1619.       fprintf (outfile, ".space    %d\n", count * size);
  1620.     }
  1621. }
  1622.  
  1623.  
  1624. /* .export */
  1625.  
  1626. void
  1627. do_export (in)
  1628.      sb *in;
  1629. {
  1630.   fprintf (outfile, ".global    %s\n", sb_name (in));
  1631. }
  1632.  
  1633. /* .print [list] [nolist] */
  1634.  
  1635. void
  1636. do_print (idx, in)
  1637.      int idx;
  1638.      sb *in;
  1639. {
  1640.   idx = sb_skip_white (idx, in);
  1641.   while (idx < in->len)
  1642.     {
  1643.       if (strncmp (in->ptr + idx, "LIST", 4) == 0)
  1644.     {
  1645.       fprintf (outfile, ".list\n");
  1646.       idx += 4;
  1647.     }
  1648.       else if (strncmp (in->ptr + idx, "NOLIST", 6) == 0)
  1649.     {
  1650.       fprintf (outfile, ".nolist\n");
  1651.       idx += 6;
  1652.     }
  1653.       idx++;
  1654.     }
  1655. }
  1656.  
  1657. /* .head */
  1658. void
  1659. do_heading (idx, in)
  1660.      int idx;
  1661.      sb *in;
  1662. {
  1663.   sb head;
  1664.   sb_new (&head);
  1665.   idx = getstring (idx, in, &head);
  1666.   fprintf (outfile, ".title    \"%s\"\n", sb_name (&head));
  1667.   sb_kill (&head);
  1668. }
  1669.  
  1670. /* .page */
  1671.  
  1672. void
  1673. do_page ()
  1674. {
  1675.   fprintf (outfile, ".eject\n");
  1676. }
  1677.  
  1678. /* .form [lin=<value>] [col=<value>] */
  1679. void
  1680. do_form (idx, in)
  1681.      int idx;
  1682.      sb *in;
  1683. {
  1684.   int lines = 60;
  1685.   int columns = 132;
  1686.   idx = sb_skip_white (idx, in);
  1687.  
  1688.   while (idx < in->len)
  1689.     {
  1690.  
  1691.       if (strncmp (in->ptr + idx, "LIN=", 4) == 0)
  1692.     {
  1693.       idx += 4;
  1694.       idx = exp_get_abs ("form LIN= needs absolute expresssion.\n", idx, in, &lines);
  1695.     }
  1696.  
  1697.       if (strncmp (in->ptr + idx, "COL=", 4) == 0)
  1698.     {
  1699.       idx += 4;
  1700.       idx = exp_get_abs ("form COL= needs absolute expresssion.\n", idx, in, &columns);
  1701.     }
  1702.  
  1703.       idx++;
  1704.     }
  1705.   fprintf (outfile, ".psize %d,%d\n", lines, columns);
  1706.  
  1707. }
  1708.  
  1709.  
  1710. /* Fetch string from the input stream,
  1711.    rules:
  1712.     'Bxyx<whitespace>      -> return 'Bxyza
  1713.     %<char>        -> return string of decimal value of x
  1714.     "<string>"        -> return string
  1715.     xyx<whitespace>     -> return xyz
  1716. */
  1717. int
  1718. get_any_string (idx, in, out, expand, pretend_quoted)
  1719.      int idx;
  1720.      sb *in;
  1721.      sb *out;
  1722.      int expand;
  1723.      int pretend_quoted;
  1724. {
  1725.   sb_reset (out);
  1726.   idx = sb_skip_white (idx, in);
  1727.  
  1728.   if (idx < in->len)
  1729.     {
  1730.       if (in->len > 2 && in->ptr[idx+1] == '\'' && ISBASE (in->ptr[idx]))
  1731.     {
  1732.       while (!ISSEP (in->ptr[idx]))
  1733.         sb_add_char (out, in->ptr[idx++]);
  1734.     }
  1735.       else if (in->ptr[idx] == '%'
  1736.            && alternate
  1737.            && expand)
  1738.     {
  1739.       int val;
  1740.       char buf[20];
  1741.       /* Turns the next expression into a string */
  1742.       idx = exp_get_abs ("% operator needs absolute expression",
  1743.                  idx + 1,
  1744.                  in,
  1745.                  &val);
  1746.       sprintf(buf, "%d", val);
  1747.       sb_add_string (out, buf);
  1748.     }
  1749.       else if (in->ptr[idx] == '"'
  1750.            || in->ptr[idx] == '<'
  1751.            || (alternate && in->ptr[idx] == '\''))
  1752.     {
  1753.       if (alternate && expand)
  1754.         {
  1755.           /* Keep the quotes */
  1756.                 sb_add_char (out,  '\"');
  1757.             
  1758.           idx =  getstring (idx, in, out);
  1759.                   sb_add_char (out,  '\"');
  1760.  
  1761.         }
  1762.       else {
  1763.         idx = getstring (idx, in, out);
  1764.       }
  1765.     }
  1766.       else 
  1767.     {
  1768.       while (idx < in->len 
  1769.          && (in->ptr[idx] == '"'
  1770.              || in->ptr[idx] == '\''
  1771.              || pretend_quoted 
  1772.              || !ISSEP (in->ptr[idx])))
  1773.         {
  1774.           if (in->ptr[idx] == '"' 
  1775.           || in->ptr[idx] == '\'')
  1776.         {
  1777.           char tchar = in->ptr[idx];
  1778.           sb_add_char (out, in->ptr[idx++]);
  1779.           while (idx < in->len
  1780.              && in->ptr[idx] != tchar)
  1781.             sb_add_char (out, in->ptr[idx++]);            
  1782.           if (idx == in->len)
  1783.             return idx;          
  1784.         }
  1785.           sb_add_char (out, in->ptr[idx++]);
  1786.         }
  1787.     }
  1788.     }
  1789.  
  1790.   return idx;
  1791. }
  1792.  
  1793.  
  1794. /* skip along sb in starting at idx, suck off whitespace a ( and more
  1795.    whitespace.  return the idx of the next char */
  1796.  
  1797. int
  1798. skip_openp (idx, in)
  1799.      int idx;
  1800.      sb *in;
  1801. {
  1802.   idx = sb_skip_white (idx, in);
  1803.   if (in->ptr[idx] != '(')
  1804.     ERROR ((stderr, "misplaced ( .\n"));
  1805.   idx = sb_skip_white (idx + 1, in);
  1806.   return idx;
  1807. }
  1808.  
  1809. /* skip along sb in starting at idx, suck off whitespace a ) and more
  1810.    whitespace.  return the idx of the next char */
  1811.  
  1812. int
  1813. skip_closep (idx, in)
  1814.      int idx;
  1815.      sb *in;
  1816. {
  1817.   idx = sb_skip_white (idx, in);
  1818.   if (in->ptr[idx] != ')')
  1819.     ERROR ((stderr, "misplaced ).\n"));
  1820.   idx = sb_skip_white (idx + 1, in);
  1821.   return idx;
  1822. }
  1823.  
  1824. /* .len */
  1825.  
  1826. int
  1827. dolen (idx, in, out)
  1828.      int idx;
  1829.      sb *in;
  1830.      sb *out;
  1831. {
  1832.  
  1833.   sb stringout;
  1834.   char buffer[10];
  1835.  
  1836.   sb_new (&stringout);
  1837.   idx = skip_openp (idx, in);
  1838.   idx = get_and_process (idx, in, &stringout);
  1839.   idx = skip_closep (idx, in);
  1840.   sprintf (buffer, "%d", stringout.len);
  1841.   sb_add_string (out, buffer);
  1842.  
  1843.   sb_kill (&stringout);
  1844.   return idx;
  1845. }
  1846.  
  1847.  
  1848. /* .instr */
  1849.  
  1850. static
  1851. int
  1852. doinstr (idx, in, out)
  1853.      int idx;
  1854.      sb *in;
  1855.      sb *out;
  1856. {
  1857.   sb string;
  1858.   sb search;
  1859.   int i;
  1860.   int start;
  1861.   int res;
  1862.   char buffer[10];
  1863.  
  1864.   sb_new (&string);
  1865.   sb_new (&search);
  1866.   idx = skip_openp (idx, in);
  1867.   idx = get_and_process (idx, in, &string);
  1868.   idx = sb_skip_comma (idx, in);
  1869.   idx = get_and_process (idx, in, &search);
  1870.   idx = sb_skip_comma (idx, in);
  1871.   if (isdigit (in->ptr[idx]))
  1872.     {
  1873.       idx = exp_get_abs (".instr needs absolute expresson.\n", idx, in, &start);
  1874.     }
  1875.   else
  1876.     {
  1877.       start = 0;
  1878.     }
  1879.   idx = skip_closep (idx, in);
  1880.   res = -1;
  1881.   for (i = start; i < string.len; i++)
  1882.     {
  1883.       if (strncmp (string.ptr + i, search.ptr, search.len) == 0)
  1884.     {
  1885.       res = i;
  1886.       break;
  1887.     }
  1888.     }
  1889.   sprintf (buffer, "%d", res);
  1890.   sb_add_string (out, buffer);
  1891.   sb_kill (&string);
  1892.   sb_kill (&search);
  1893.   return idx;
  1894. }
  1895.  
  1896.  
  1897. static int
  1898. dosubstr (idx, in, out)
  1899.      int idx;
  1900.      sb *in;
  1901.      sb *out;
  1902. {
  1903.   sb string;
  1904.   int pos;
  1905.   int len;
  1906.   sb_new (&string);
  1907.  
  1908.   idx = skip_openp (idx, in);
  1909.   idx = get_and_process (idx, in, &string);
  1910.   idx = sb_skip_comma (idx, in);
  1911.   idx = exp_get_abs ("need absolute position.\n", idx, in, &pos);
  1912.   idx = sb_skip_comma (idx, in);
  1913.   idx = exp_get_abs ("need absolute length.\n", idx, in, &len);
  1914.   idx = skip_closep (idx, in);
  1915.  
  1916.  
  1917.   if (len < 0 || pos < 0 ||
  1918.       pos > string.len
  1919.       || pos + len > string.len)
  1920.     {
  1921.       sb_add_string (out, " ");
  1922.     }
  1923.   else 
  1924.     {
  1925.       sb_add_char (out, '"');
  1926.       while (len > 0)
  1927.     {
  1928.       sb_add_char (out, string.ptr[pos++]);
  1929.       len--;
  1930.     }
  1931.       sb_add_char (out, '"');
  1932.     }
  1933.   sb_kill(&string);
  1934.   return idx;
  1935. }
  1936.  
  1937. /* scan line, change tokens in the hash table to their replacements */
  1938. void
  1939. process_assigns (idx, in, buf)
  1940.      int idx;
  1941.      sb *in;
  1942.      sb *buf;
  1943. {
  1944.   while (idx < in->len)
  1945.     {
  1946.       hash_entry *ptr;
  1947.       if (in->ptr[idx] == '\\'
  1948.       && in->ptr[idx + 1] == '&')
  1949.     {
  1950.       idx = condass_lookup_name (in, idx + 2, buf, 1);
  1951.     }
  1952.       else if (in->ptr[idx] == '\\'
  1953.            && in->ptr[idx + 1] == '$')
  1954.     {
  1955.       idx = condass_lookup_name (in, idx + 2, buf, 0);
  1956.     }
  1957.       else if (idx + 3 < in->len
  1958.            && in->ptr[idx] == '.'
  1959.            && in->ptr[idx + 1] == 'L'
  1960.            && in->ptr[idx + 2] == 'E'
  1961.            && in->ptr[idx + 3] == 'N')
  1962.     idx = dolen (idx + 4, in, buf);
  1963.       else if (idx + 6 < in->len
  1964.            && in->ptr[idx] == '.'
  1965.            && in->ptr[idx + 1] == 'I'
  1966.            && in->ptr[idx + 2] == 'N'
  1967.            && in->ptr[idx + 3] == 'S'
  1968.            && in->ptr[idx + 4] == 'T'
  1969.            && in->ptr[idx + 5] == 'R')
  1970.     idx = doinstr (idx + 6, in, buf);
  1971.       else if (idx + 7 < in->len
  1972.            && in->ptr[idx] == '.'
  1973.            && in->ptr[idx + 1] == 'S'
  1974.            && in->ptr[idx + 2] == 'U'
  1975.            && in->ptr[idx + 3] == 'B'
  1976.            && in->ptr[idx + 4] == 'S'
  1977.            && in->ptr[idx + 5] == 'T'
  1978.            && in->ptr[idx + 6] == 'R')
  1979.     idx = dosubstr (idx + 7, in, buf);
  1980.       else if (ISFIRSTCHAR (in->ptr[idx]))
  1981.     {
  1982.       /* may be a simple name subsitution, see if we have a word */
  1983.       sb acc;
  1984.       int cur = idx + 1;
  1985.       while (cur < in->len
  1986.          && (ISNEXTCHAR (in->ptr[cur])))
  1987.         cur++;
  1988.  
  1989.       sb_new (&acc);
  1990.       sb_add_buffer (&acc, in->ptr + idx, cur - idx);
  1991.       ptr = hash_lookup (&assign_hash_table, &acc);
  1992.       if (ptr)
  1993.         {
  1994.           /* Found a definition for it */
  1995.           sb_add_sb (buf, &ptr->value.s);
  1996.         }
  1997.       else
  1998.         {
  1999.           /* No definition, just copy the word */
  2000.           sb_add_sb (buf, &acc);
  2001.         }
  2002.       sb_kill (&acc);
  2003.       idx = cur;
  2004.     }
  2005.       else
  2006.     {
  2007.       sb_add_char (buf, in->ptr[idx++]);
  2008.     }
  2009.     }
  2010. }
  2011.  
  2012. static int
  2013. get_and_process (idx, in, out)
  2014.      int idx;
  2015.      sb *in;
  2016.      sb *out;
  2017. {
  2018.   sb t;
  2019.   sb_new (&t);
  2020.   idx = get_any_string (idx, in, &t, 1, 0);
  2021.   process_assigns (0, &t, out);
  2022.   sb_kill (&t);
  2023.   return idx;
  2024. }
  2025.  
  2026. static
  2027. void
  2028. process_file ()
  2029. {
  2030.   sb line;
  2031.   sb t1, t2;
  2032.   sb acc;
  2033.   sb label_in;
  2034.   int more;
  2035.  
  2036.   sb_new (&line);
  2037.   sb_new (&t1);
  2038.   sb_new (&t2);
  2039.   sb_new(&acc);
  2040.   sb_new (&label_in);
  2041.   sb_reset (&line);
  2042.   more = get_line (&line);
  2043.   while (more)
  2044.     {
  2045.       /* Find any label and pseudo op that we're intested in */
  2046.       int l;
  2047.       if (line.len == 0)
  2048.     {
  2049.       if (condass_on ())
  2050.         fprintf (outfile, "\n");
  2051.     }
  2052.       else
  2053.     {
  2054.       l = grab_label (&line, &label_in);
  2055.       sb_reset (&label);            
  2056.       if (label_in.len)
  2057.         {
  2058.           /* Munge any label */
  2059.  
  2060.           
  2061.           process_assigns (0, &label_in, &label);
  2062.         }
  2063.  
  2064.       if (line.ptr[l] == ':')
  2065.         l++;
  2066.       while (ISWHITE (line.ptr[l]) && l < line.len)
  2067.         l++;
  2068.  
  2069.       if (l < line.len)
  2070.         {
  2071.           if (process_pseudo_op (l, &line, &acc))
  2072.         {
  2073.  
  2074.  
  2075.  
  2076.         }
  2077.           else if (condass_on ())
  2078.         {
  2079.           if (macro_op (l, &line))
  2080.             {
  2081.  
  2082.  
  2083.             }
  2084.           else
  2085.             {
  2086.               {
  2087.             if (label.len)
  2088.               {
  2089.                 fprintf (outfile, "%s:\t", sb_name (&label));
  2090.               }
  2091.             else
  2092.               fprintf (outfile, "\t");
  2093.             sb_reset(&t1);
  2094.             process_assigns (l, &line, &t1);
  2095.             sb_reset (&t2);
  2096.             change_base (0, &t1, &t2);
  2097.             fprintf (outfile, "%s\n", sb_name (&t2));
  2098.               }
  2099.             }
  2100.         }
  2101.         }
  2102.       else {
  2103.         /* Only a label on this line */
  2104.         if (label.len && condass_on())
  2105.           {
  2106.         fprintf (outfile, "%s:\n", sb_name (&label));
  2107.           }
  2108.       }
  2109.     }
  2110.  
  2111.       if (had_end)
  2112.     break;
  2113.       sb_reset (&line);
  2114.       more = get_line (&line);
  2115.     }
  2116.  
  2117.   if (!had_end)
  2118.     WARNING ((stderr, "END missing from end of file.\n"));
  2119. }
  2120.  
  2121.  
  2122.  
  2123.  
  2124.  
  2125. static void
  2126. free_old_entry (ptr)
  2127.      hash_entry *ptr;
  2128. {
  2129.   if (ptr)
  2130.     {
  2131.       if (ptr->type == hash_string)
  2132.     sb_kill(&ptr->value.s);
  2133.     }
  2134. }
  2135.  
  2136. /* name: .ASSIGNA <value> */
  2137.  
  2138. void
  2139. do_assigna (idx, in)
  2140.      int idx;
  2141.      sb *in;
  2142. {
  2143.   sb tmp;
  2144.   int val;
  2145.   sb_new (&tmp);
  2146.  
  2147.   process_assigns (idx, in, &tmp);
  2148.   idx = exp_get_abs (".ASSIGNA needs constant expression argument.\n", 0, &tmp, &val);
  2149.  
  2150.   if (!label.len)
  2151.     {
  2152.       ERROR ((stderr, ".ASSIGNA without label.\n"));
  2153.     }
  2154.   else
  2155.     {
  2156.       hash_entry *ptr = hash_create (&vars, &label);
  2157.       free_old_entry (ptr);
  2158.       ptr->type = hash_integer;
  2159.       ptr->value.i = val;
  2160.     }
  2161.   sb_kill (&tmp);
  2162. }
  2163.  
  2164. /* name: .ASSIGNC <string> */
  2165.  
  2166. void
  2167. do_assignc (idx, in)
  2168.      int idx;
  2169.      sb *in;
  2170. {
  2171.   sb acc;
  2172.   sb_new (&acc);
  2173.   idx = getstring (idx, in, &acc);
  2174.  
  2175.   if (!label.len)
  2176.     {
  2177.       ERROR ((stderr, ".ASSIGNS without label.\n"));
  2178.     }
  2179.   else
  2180.     {
  2181.       hash_entry *ptr = hash_create (&vars, &label);
  2182.       free_old_entry (ptr);
  2183.       ptr->type = hash_string;
  2184.       sb_new (&ptr->value.s);
  2185.       sb_add_sb (&ptr->value.s, &acc);
  2186.     }
  2187.   sb_kill (&acc);
  2188. }
  2189.  
  2190.  
  2191. /* name: .REG (reg) */
  2192.  
  2193. static void
  2194. do_reg (idx, in)
  2195.      int idx;
  2196.      sb *in;
  2197. {
  2198.   /* remove reg stuff from inside parens */
  2199.   sb what;
  2200.   idx = skip_openp (idx, in);
  2201.   sb_new (&what);
  2202.   while (idx < in->len && in->ptr[idx] != ')')
  2203.     {
  2204.       sb_add_char (&what, in->ptr[idx]);
  2205.       idx++;
  2206.     }
  2207.   hash_add_to_string_table (&assign_hash_table, &label, &what, 1);
  2208.   sb_kill (&what);
  2209. }
  2210.  
  2211.  
  2212. static int
  2213. condass_lookup_name (inbuf, idx, out, warn)
  2214.      sb *inbuf;
  2215.      int idx;
  2216.      sb *out;
  2217.      int warn;
  2218. {
  2219.   hash_entry *ptr;
  2220.   sb condass_acc;
  2221.   sb_new (&condass_acc);
  2222.  
  2223.   while (idx < inbuf->len
  2224.      && ISNEXTCHAR (inbuf->ptr[idx]))
  2225.     {
  2226.       sb_add_char (&condass_acc, inbuf->ptr[idx++]);
  2227.     }
  2228.  
  2229.   if (inbuf->ptr[idx] == '\'')
  2230.     idx++;
  2231.   ptr = hash_lookup (&vars, &condass_acc);
  2232.  
  2233.  
  2234.   if (!ptr)
  2235.     {
  2236.       if (warn) 
  2237.     {
  2238.       WARNING ((stderr, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc)));
  2239.     }
  2240.       else 
  2241.     {
  2242.       sb_add_string (out, "0");
  2243.     }
  2244.     }
  2245.   else
  2246.     {
  2247.       if (ptr->type == hash_integer)
  2248.     {
  2249.       char buffer[30];
  2250.       sprintf (buffer, "%d", ptr->value.i);
  2251.       sb_add_string (out, buffer);
  2252.     }
  2253.       else
  2254.     {
  2255.       sb_add_sb (out, &ptr->value.s);
  2256.     }
  2257.     }
  2258.   sb_kill (&condass_acc);
  2259.   return idx;
  2260. }
  2261.  
  2262. #define EQ 1
  2263. #define NE 2
  2264. #define GE 3
  2265. #define LT 4
  2266. #define LE 5
  2267. #define GT 6
  2268. #define NEVER 7
  2269.  
  2270. int
  2271. whatcond (idx, in, val)
  2272.      int idx;
  2273.      sb *in;
  2274.      int *val;
  2275. {
  2276.   int cond;
  2277.   char *p;
  2278.   idx = sb_skip_white (idx, in);
  2279.   p = in->ptr + idx;
  2280.   if (p[0] == 'E' && p[1] == 'Q')
  2281.     cond = EQ;
  2282.   else if (p[0] == 'N' && p[1] == 'E')
  2283.     cond = NE;
  2284.   else if (p[0] == 'L' && p[1] == 'T')
  2285.     cond = LT;
  2286.   else if (p[0] == 'L' && p[1] == 'E')
  2287.     cond = LE;
  2288.   else if (p[0] == 'G' && p[1] == 'T')
  2289.     cond = GT;
  2290.   else if (p[0] == 'G' && p[1] == 'E')
  2291.     cond = GE;
  2292.   else
  2293.     {
  2294.       ERROR ((stderr, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n"));
  2295.       cond = NEVER;
  2296.     }
  2297.   idx = sb_skip_white (idx + 2, in);
  2298.   *val = cond;
  2299.   return idx;
  2300. }
  2301.  
  2302. int
  2303. istrue (idx, in)
  2304.      int idx;
  2305.      sb *in;
  2306. {
  2307.   int res;
  2308.   sb acc_a;
  2309.   sb cond;
  2310.   sb acc_b;
  2311.   sb_new (&acc_a);
  2312.   sb_new (&cond);
  2313.   sb_new (&acc_b);
  2314.   idx = sb_skip_white (idx, in);
  2315.  
  2316.   if (in->ptr[idx] == '"')
  2317.     {
  2318.       int cond;
  2319.       int same;
  2320.       /* This is a string comparision */
  2321.       idx = getstring (idx, in, &acc_a);
  2322.       idx = whatcond (idx, in, &cond);
  2323.       idx = getstring (idx, in, &acc_b);
  2324.       same = acc_a.len == acc_b.len && (strncmp (acc_a.ptr, acc_b.ptr, acc_a.len) == 0);
  2325.  
  2326.       if (cond != EQ && cond != NE)
  2327.     {
  2328.       ERROR ((stderr, "Comparison operator for strings must be EQ or NE\n"));
  2329.       res = 0;
  2330.     }
  2331.       else
  2332.     res = cond == EQ && same;
  2333.     }
  2334.   else
  2335.     /* This is a numeric expression */
  2336.     {
  2337.       int vala;
  2338.       int valb;
  2339.       int cond;
  2340.       idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &vala);
  2341.       idx = whatcond (idx, in, &cond);
  2342.       idx = sb_skip_white (idx, in);
  2343.       if (in->ptr[idx] == '"')
  2344.     {
  2345.       WARNING ((stderr, "String compared against expression.\n"));
  2346.       res = 0;
  2347.     }
  2348.       else
  2349.     {
  2350.       idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &valb);
  2351.       switch (cond)
  2352.         {
  2353.         case EQ:
  2354.           res = vala == valb;
  2355.           break;
  2356.         case NE:
  2357.           res = vala != valb;
  2358.           break;
  2359.         case LT:
  2360.           res = vala < valb;
  2361.           break;
  2362.         case LE:
  2363.           res = vala <= valb;
  2364.           break;
  2365.         case GT:
  2366.           res = vala > valb;
  2367.           break;
  2368.         case GE:
  2369.           res = vala >= valb;
  2370.           break;
  2371.         case NEVER:
  2372.           res = 0;
  2373.           break;
  2374.         }
  2375.     }
  2376.     }
  2377.  
  2378.   sb_kill (&acc_a);
  2379.   sb_kill (&cond);
  2380.   sb_kill (&acc_b);
  2381.   return res;
  2382. }
  2383.  
  2384. /* .AIF */
  2385. static void
  2386. do_aif (idx, in)
  2387.      int idx;
  2388.      sb *in;
  2389. {
  2390.   if (ifi >= IFNESTING)
  2391.     {
  2392.       FATAL ((stderr, "AIF nesting unreasonable.\n"));
  2393.     }
  2394.   ifi++;
  2395.   ifstack[ifi].on = ifstack[ifi-1].on ? istrue (idx, in) : 0;
  2396.   ifstack[ifi].hadelse = 0;
  2397. }
  2398.  
  2399.  
  2400. /* .AELSE */
  2401. static void
  2402. do_aelse ()
  2403. {
  2404.   ifstack[ifi].on = ifstack[ifi-1].on ? !ifstack[ifi].on : 0;
  2405.   if (ifstack[ifi].hadelse)
  2406.     {
  2407.       ERROR ((stderr, "Multiple AELSEs in AIF.\n"));
  2408.     }
  2409.   ifstack[ifi].hadelse = 1;
  2410. }
  2411.  
  2412.  
  2413. /* .AENDI */
  2414. static void
  2415. do_aendi ()
  2416. {
  2417.   if (ifi != 0)
  2418.     {
  2419.       ifi--;
  2420.     }
  2421.   else
  2422.     {
  2423.       ERROR ((stderr, "AENDI without AIF.\n"));
  2424.     }
  2425. }
  2426.  
  2427. static int
  2428. condass_on ()
  2429. {
  2430.   return ifstack[ifi].on;
  2431. }
  2432.  
  2433.  
  2434. /* Read input lines till we get to a TO string.
  2435.    Increase nesting depth if we geta FROM string.
  2436.    Put the results into sb at PTR. */
  2437.  
  2438. static void
  2439. buffer_and_nest (from, to, ptr)
  2440.      char *from;
  2441.      char *to;
  2442.      sb *ptr;
  2443. {
  2444.   int from_len = strlen (from);
  2445.   int to_len = strlen (to);
  2446.   int depth = 1;
  2447.   int line_start = ptr->len;
  2448.   int line = linecount ();
  2449.  
  2450.   int more = get_line (ptr);
  2451.  
  2452.   while (more)
  2453.     {
  2454.       /* Try and find the first pseudo op on the line */
  2455.       int i = line_start;
  2456.  
  2457.       if (!alternate) 
  2458.     {
  2459.       /* With normal syntax we can suck what we want till we get to the dot.
  2460.          With the alternate, labels have to start in the first column, since
  2461.          we cant tell what's a label and whats a pseudoop */
  2462.  
  2463.       /* Skip leading whitespace */
  2464.       while (i < ptr->len
  2465.          && ISWHITE (ptr->ptr[i]))
  2466.     i++;
  2467.  
  2468.       /* Skip over a label */
  2469.       while (i < ptr->len
  2470.          && ISNEXTCHAR (ptr->ptr[i]))
  2471.     i++;
  2472.  
  2473.       /* And a colon */
  2474.       if (i < ptr->len
  2475.       && ptr->ptr[i] == ':')
  2476.     i++;
  2477.  
  2478.     }
  2479.       /* Skip trailing whitespace */
  2480.       while (i < ptr->len
  2481.          && ISWHITE (ptr->ptr[i]))
  2482.     i++;
  2483.  
  2484.       if (i < ptr->len && (ptr->ptr[i] == '.' 
  2485.                || alternate))
  2486.     {
  2487.       if (ptr->ptr[i] == '.')
  2488.           i++;
  2489.       if (strncmp (ptr->ptr + i, from, from_len) == 0)
  2490.         depth++;
  2491.       if (strncmp (ptr->ptr + i, to, to_len) == 0)
  2492.         {
  2493.           depth--;
  2494.           if (depth == 0)
  2495.         {
  2496.           /* Reset the string to not include the ending rune */
  2497.           ptr->len = line_start;
  2498.           break;
  2499.         }
  2500.         }
  2501.     }
  2502.  
  2503.       /* Add a CR to the end and keep running */
  2504.       sb_add_char (ptr, '\n');
  2505.       line_start = ptr->len;
  2506.       more = get_line (ptr);
  2507.     }
  2508.  
  2509.  
  2510.   if (depth)
  2511.     FATAL ((stderr, "End of file whilst inside %s, started on line %d.\n", from, line));
  2512. }
  2513.  
  2514.  
  2515. /* .ENDR */
  2516. void
  2517. do_aendr ()
  2518. {
  2519.   ERROR ((stderr, "AENDR without a AREPEAT.\n"));
  2520. }
  2521.  
  2522. /* .AWHILE */
  2523.  
  2524. static
  2525. void
  2526. do_awhile (idx, in)
  2527.      int idx;
  2528.      sb *in;
  2529. {
  2530.   sb exp;
  2531.  
  2532.   sb sub;
  2533.  
  2534.   int doit;
  2535.   sb_new (&sub);
  2536.   sb_new (&exp);
  2537.  
  2538.   process_assigns (idx, in, &exp);
  2539.   doit = istrue (0, &exp);
  2540.  
  2541.   buffer_and_nest ("AWHILE", "AENDW", &sub);
  2542.  
  2543.   /* Turn
  2544.          .AWHILE exp
  2545.          foo
  2546.     .AENDW
  2547.      into
  2548.         foo
  2549.     .AWHILE exp
  2550.     foo
  2551.     .ENDW
  2552.    */
  2553.  
  2554.   if (doit)
  2555.     {
  2556.       int index = include_next_index ();
  2557.  
  2558.       sb copy;
  2559.       sb_new (©);
  2560.       sb_add_sb (©, &sub);
  2561.       sb_add_sb (©, in);
  2562.       sb_add_string (©, "\n");
  2563.       sb_add_sb (©, &sub);
  2564.       sb_add_string (©, "\t.AENDW\n");
  2565.       /* Push another WHILE */
  2566.       include_buf (&exp, ©, include_while, index);
  2567.       sb_kill (©);
  2568.     }
  2569.   sb_kill (&exp);
  2570.   sb_kill (&sub);
  2571. }
  2572.  
  2573.  
  2574. /* .AENDW */
  2575.  
  2576. static void
  2577. do_aendw ()
  2578. {
  2579.   ERROR ((stderr, "AENDW without a AENDW.\n"));
  2580. }
  2581.  
  2582.  
  2583. /* .EXITM
  2584.    
  2585.    Pop things off the include stack until the type and index changes */
  2586.  
  2587. static void
  2588. do_exitm ()
  2589. {
  2590.   include_type type = sp->type;
  2591.   if (type == include_repeat
  2592.       || type == include_while
  2593.       || type == include_macro)
  2594.     {
  2595.       int index = sp->index;
  2596.       include_pop ();
  2597.       while (sp->index == index
  2598.          && sp->type == type)
  2599.     {
  2600.       include_pop ();
  2601.     }
  2602.     }
  2603. }
  2604.  
  2605. /* .AREPEAT */
  2606.  
  2607. static void
  2608. do_arepeat (idx, in)
  2609.      int idx;
  2610.      sb *in;
  2611. {
  2612.   sb exp;            /* buffer with expression in it */
  2613.   sb copy;            /* expanded repeat block */
  2614.   sb sub;            /* contents of AREPEAT */
  2615.   int rc;
  2616.   char buffer[30];
  2617.   sb_new (&exp);
  2618.   sb_new (©);
  2619.   sb_new (&sub);
  2620.   process_assigns (idx, in, &exp);
  2621.   idx = exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp, &rc);
  2622.   buffer_and_nest ("AREPEAT", "AENDR", &sub);
  2623.   if (rc > 0)
  2624.     {
  2625.       /* Push back the text following the repeat, and another repeat block
  2626.      so
  2627.      .AREPEAT 20
  2628.      foo
  2629.      .AENDR
  2630.      gets turned into
  2631.      foo
  2632.      .AREPEAT 19
  2633.      foo
  2634.      .AENDR
  2635.      */
  2636.       int index = include_next_index ();
  2637.       sb_add_sb (©, &sub);
  2638.       if (rc > 1)
  2639.     {
  2640.       sprintf (buffer, "\t.AREPEAT    %d\n", rc - 1);
  2641.       sb_add_string (©, buffer);
  2642.       sb_add_sb (©, &sub);
  2643.       sb_add_string (©, "    .AENDR\n");
  2644.     }
  2645.  
  2646.       include_buf (&exp, ©, include_repeat, index);
  2647.     }
  2648.   sb_kill (&exp);
  2649.   sb_kill (&sub);
  2650.   sb_kill (©);
  2651. }
  2652.  
  2653. /* .ENDM */
  2654.  
  2655. static void
  2656. do_endm ()
  2657. {
  2658.   ERROR ((stderr, ".ENDM without a matching .MACRO.\n"));
  2659. }
  2660.  
  2661.  
  2662. /* MARRO PROCESSING */
  2663.  
  2664. static int number;
  2665. hash_table macro_table;
  2666.  
  2667. /* Understand
  2668.  
  2669.    .MACRO <name>
  2670.    stuff
  2671.    .ENDM
  2672. */
  2673.  
  2674. static int
  2675. do_formals (macro, idx, in)
  2676.      macro_entry *macro;
  2677.      int idx;
  2678.      sb *in;
  2679. {
  2680.   formal_entry **p = ¯o->formals;
  2681.   macro->formal_count = 0;
  2682.   hash_new_table (5, ¯o->formal_hash);
  2683.   while (idx < in->len)
  2684.     {
  2685.       formal_entry *formal;
  2686.  
  2687.       formal = (formal_entry *) xmalloc (sizeof (formal_entry));
  2688.  
  2689.       sb_new (&formal->name);
  2690.       sb_new (&formal->def);
  2691.       sb_new (&formal->actual);
  2692.  
  2693.       idx = sb_skip_white (idx, in);
  2694.       idx = get_token (idx, in, &formal->name);
  2695.       if (formal->name.len == 0)
  2696.     break;
  2697.       idx = sb_skip_white (idx, in);
  2698.       if (formal->name.len)
  2699.     {
  2700.       /* This is a formal */
  2701.       if (idx < in->len && in->ptr[idx] == '=')
  2702.         {
  2703.           /* Got a default */
  2704.           idx = get_any_string (idx + 1, in, &formal->def, 1, 0);
  2705.         }
  2706.     }
  2707.  
  2708.       {
  2709.     /* Add to macro's hash table */
  2710.  
  2711.     hash_entry *p = hash_create (¯o->formal_hash, &formal->name);
  2712.     p->type = hash_formal;
  2713.     p->value.f = formal;
  2714.       }
  2715.  
  2716.       formal->index = macro->formal_count;
  2717.       idx = sb_skip_comma (idx, in);
  2718.       macro->formal_count++;
  2719.       *p = formal;
  2720.       p = &formal->next;
  2721.     }
  2722.   return idx;
  2723. }
  2724.  
  2725. /* Parse off LOCAL n1, n2,... Invent a label name for it */
  2726. static
  2727. void 
  2728. do_local (idx, line)
  2729.      int idx;
  2730.      sb *line;
  2731. {
  2732.   static int ln;
  2733.   sb acc;
  2734.   sb sub;
  2735.   char subs[10];
  2736.   sb_new (&acc);
  2737.   sb_new (&sub);
  2738.   idx = sb_skip_white (idx, line);
  2739.   while (!eol(idx, line))
  2740.     {
  2741.       sb_reset (&acc);
  2742.       sb_reset (&sub);
  2743.       ln++;
  2744.       sprintf(subs, "LL%04x", ln);
  2745.       idx =  get_token(idx, line, &acc);
  2746.       sb_add_string (&sub, subs);
  2747.       hash_add_to_string_table (&assign_hash_table, &acc, &sub, 1);
  2748.       idx = sb_skip_comma (idx, line);
  2749.     }
  2750.   sb_kill (&sub);
  2751.   sb_kill (&acc);
  2752. }
  2753.  
  2754. static
  2755. void
  2756. do_macro (idx, in)
  2757.      int idx;
  2758.      sb *in;
  2759. {
  2760.   macro_entry *macro;
  2761.   sb name;
  2762.  
  2763.   macro = (macro_entry *) xmalloc (sizeof (macro_entry));
  2764.   sb_new (¯o->sub);
  2765.   sb_new (&name);
  2766.  
  2767.   macro->formal_count = 0;
  2768.   macro->formals = 0;
  2769.  
  2770.   idx = sb_skip_white (idx, in);
  2771.   buffer_and_nest ("MACRO", "ENDM", ¯o->sub);
  2772.   if (label.len)
  2773.     {
  2774.  
  2775.       sb_add_sb (&name, &label);
  2776.       if (in->ptr[idx] == '(')
  2777.     {
  2778.       /* It's the label: MACRO (formals,...)  sort */
  2779.       idx = do_formals (macro, idx + 1, in);
  2780.       if (in->ptr[idx] != ')')
  2781.         ERROR ((stderr, "Missing ) after formals.\n"));
  2782.     }
  2783.       else {
  2784.     /* It's the label: MACRO formals,...  sort */
  2785.     idx = do_formals (macro, idx, in);
  2786.       }
  2787.     }
  2788.   else
  2789.     {
  2790.       idx = get_token (idx, in, &name);
  2791.       idx = sb_skip_white (idx, in);
  2792.       idx = do_formals (macro, idx, in);
  2793.     }
  2794.  
  2795.   /* and stick it in the macro hash table */
  2796.   hash_create (¯o_table, &name)->value.m = macro;
  2797. }
  2798.  
  2799. static
  2800. int
  2801. get_token (idx, in, name)
  2802.      int idx;
  2803.      sb *in;
  2804.      sb *name;
  2805. {
  2806.   if (idx < in->len
  2807.       && ISFIRSTCHAR (in->ptr[idx]))
  2808.     {
  2809.       sb_add_char (name, in->ptr[idx++]);
  2810.       while (idx < in->len
  2811.          && ISNEXTCHAR (in->ptr[idx]))
  2812.     {
  2813.       sb_add_char (name, in->ptr[idx++]);
  2814.     }
  2815.     }
  2816.   /* Ignore trailing & */
  2817.   if (alternate && idx < in->len && in->ptr[idx] == '&')
  2818.     idx++;
  2819.   return idx;
  2820. }
  2821.  
  2822. /* Scan a token, but stop if a ' is seen */
  2823. static int
  2824. get_apost_token (idx, in, name, kind)
  2825.      int idx;
  2826.      sb *in;
  2827.      sb *name;
  2828.      int kind;
  2829. {
  2830.   idx = get_token (idx, in, name);
  2831.   if (idx < in->len && in->ptr[idx] == kind)
  2832.     idx++;
  2833.   return idx;
  2834. }
  2835.  
  2836. static int
  2837. sub_actual (src, in, t, m, kind, out, copyifnotthere)
  2838.      int src;
  2839.      sb *in;
  2840.      sb *t;
  2841.      macro_entry *m;
  2842.      int kind;
  2843.      sb *out;
  2844.      int copyifnotthere;
  2845. {
  2846.   /* This is something to take care of */
  2847.   hash_entry *ptr;
  2848.   src = get_apost_token (src, in, t, kind);
  2849.   /* See if it's in the macro's hash table */
  2850.   ptr = hash_lookup (&m->formal_hash, t);
  2851.   if (ptr)
  2852.     {
  2853.       if (ptr->value.f->actual.len)
  2854.     {
  2855.       sb_add_sb (out, &ptr->value.f->actual);
  2856.     }
  2857.       else
  2858.     {
  2859.       sb_add_sb (out, &ptr->value.f->def);
  2860.     }
  2861.     }
  2862.   else if (copyifnotthere)
  2863.     {
  2864.       sb_add_sb (out, t);
  2865.     }
  2866.   else 
  2867.     {
  2868.       sb_add_char (out, '\\');
  2869.       sb_add_sb (out, t);
  2870.     }
  2871.   return src;
  2872. }
  2873.  
  2874. static
  2875. void
  2876. macro_expand (name, idx, in, m)
  2877.      sb *name;
  2878.      int idx;
  2879.      sb *in;
  2880.      macro_entry *m;
  2881. {
  2882.   sb t;
  2883.   sb out;
  2884.   hash_entry *ptr;
  2885.   formal_entry *f;
  2886.   int is_positional = 0;
  2887.   int is_keyword = 0;
  2888.  
  2889.   sb_new (&t);
  2890.   sb_new (&out);
  2891.   
  2892.   /* Reset any old value the actuals may have */
  2893.   for (f = m->formals; f; f = f->next)
  2894.       sb_reset (&f->actual);
  2895.   f = m->formals;
  2896.   /* Peel off the actuals and store them away in the hash tables' actuals */
  2897.   while (!eol(idx, in))
  2898.     {
  2899.       int scan;
  2900.       idx = sb_skip_white (idx, in);
  2901.       /* Look and see if it's a positional or keyword arg */
  2902.       scan = idx;
  2903.       while (scan < in->len
  2904.          && !ISSEP (in->ptr[scan])
  2905.          && (!alternate && in->ptr[scan] != '='))
  2906.     scan++;
  2907.       if (scan < in->len && (!alternate) && in->ptr[scan] == '=')
  2908.     {
  2909.       is_keyword = 1;
  2910.       if (is_positional)
  2911.         {
  2912.           ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
  2913.           return;
  2914.         }
  2915.       /* This is a keyword arg, fetch the formal name and
  2916.          then the actual stuff */
  2917.       sb_reset (&t);
  2918.       idx = get_token (idx, in, &t);
  2919.       if (in->ptr[idx] != '=')
  2920.         ERROR ((stderr, "confused about formal params.\n"));
  2921.  
  2922.       /* Lookup the formal in the macro's list */
  2923.       ptr = hash_lookup (&m->formal_hash, &t);
  2924.       if (!ptr)
  2925.         {
  2926.           ERROR ((stderr, "MACRO formal argument %s does not exist.\n", sb_name (&t)));
  2927.           return;
  2928.         }
  2929.       else
  2930.         {
  2931.           /* Insert this value into the right place */
  2932.           sb_reset (&ptr->value.f->actual);
  2933.           idx = get_any_string (idx + 1, in, &ptr->value.f->actual, 0, 0);
  2934.         }
  2935.     }
  2936.       else
  2937.     {
  2938.       /* This is a positional arg */
  2939.       is_positional = 1;
  2940.       if (is_keyword)
  2941.         {
  2942.           ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
  2943.           return;
  2944.         }
  2945.       if (!f)
  2946.         {
  2947.           ERROR ((stderr, "Too many positional arguments.\n"));
  2948.           return;
  2949.         }
  2950.  
  2951.       sb_reset (&f->actual);
  2952.       idx = get_any_string (idx, in, &f->actual, 1, 0);
  2953.       f = f->next;
  2954.     }
  2955.       idx = sb_skip_comma (idx, in);
  2956.     }
  2957.  
  2958.   /* Copy the stuff from the macro buffer into a safe place and substitute any args */
  2959.  
  2960.   {
  2961.     int src = 0;
  2962.     int inquote = 0;
  2963.     sb *in = &m->sub;
  2964.     sb_reset (&out);
  2965.  
  2966.     while (src < in->len)
  2967.       {
  2968.     if (in->ptr[src] == '&')
  2969.       {
  2970.         sb_reset (&t);
  2971.         src = sub_actual (src + 1, in, &t, m, '&', &out, 0);
  2972.       }
  2973.     else if (in->ptr[src] == '\\')
  2974.       {
  2975.         src++;
  2976.         if (in->ptr[src] == comment_char)
  2977.           {
  2978.         /* This is a comment, just drop the rest of the line */
  2979.         while (src < in->len
  2980.                && in->ptr[src] != '\n')
  2981.           src++;
  2982.  
  2983.           }
  2984.         else if (in->ptr[src] == '(')
  2985.           {
  2986.         /* Sub in till the next ')' literally */
  2987.         src++;
  2988.         while (src < in->len && in->ptr[src] != ')')
  2989.           {
  2990.             sb_add_char (&out, in->ptr[src++]);
  2991.           }
  2992.         if (in->ptr[src] == ')')
  2993.           src++;
  2994.         else
  2995.           ERROR ((stderr, "Missplaced ).\n"));
  2996.           }
  2997.         else if (in->ptr[src] == '@')
  2998.           {
  2999.         /* Sub in the macro invocation number */
  3000.  
  3001.         char buffer[6];
  3002.         src++;
  3003.         sprintf (buffer, "%05d", number);
  3004.         sb_add_string (&out, buffer);
  3005.           }
  3006.         else if (in->ptr[src] == '&')
  3007.           {
  3008.         /* This is a preprocessor variable name, we don't do them
  3009.            here */
  3010.         sb_add_char (&out, '\\');
  3011.         sb_add_char (&out, '&');
  3012.         src++;
  3013.           }
  3014.         else
  3015.           {
  3016.         sb_reset (&t);
  3017.         src = sub_actual (src, in, &t, m, '\'', &out, 0);
  3018.           }
  3019.       }
  3020.     else if (ISFIRSTCHAR (in->ptr[src]) && alternate)
  3021.       {
  3022.         sb_reset (&t);
  3023.         src = sub_actual (src, in, &t, m, '\'', &out, 1);
  3024.       }
  3025.     else if (ISCOMMENTCHAR (in->ptr[src])
  3026.          && src + 1 <  in->len
  3027.          && ISCOMMENTCHAR (in->ptr[src+1])
  3028.          && !inquote)
  3029.       {
  3030.         /* Two comment chars in a row cause the rest of the line to be dropped */
  3031.         while (src < in->len && in->ptr[src] != '\n')
  3032.           src++;
  3033.       }
  3034.     else if (in->ptr[src] == '"') 
  3035.       {
  3036.         inquote = !inquote;
  3037.         sb_add_char (&out, in->ptr[src++]);
  3038.       }
  3039.     else
  3040.       {
  3041.         sb_add_char (&out, in->ptr[src++]);
  3042.       }
  3043.       }
  3044.     include_buf (name, &out, include_macro, include_next_index ());
  3045.   }
  3046.   sb_kill (&t);
  3047.   sb_kill (&out);
  3048.   number++;
  3049. }
  3050.  
  3051. static int
  3052. macro_op (idx, in)
  3053.      int idx;
  3054.      sb *in;
  3055. {
  3056.   int res = 0;
  3057.   /* The macro name must be the first thing on the line */
  3058.   if (idx < in->len)
  3059.     {
  3060.       sb name;
  3061.       hash_entry *ptr;
  3062.       sb_new (&name);
  3063.       idx = get_token (idx, in, &name);
  3064.  
  3065.       if (name.len)
  3066.     {
  3067.       /* Got a name, look it up */
  3068.  
  3069.       ptr = hash_lookup (¯o_table, &name);
  3070.  
  3071.       if (ptr)
  3072.         {
  3073.           /* It's in the table, copy out the stuff and convert any macro args */
  3074.           macro_expand (&name, idx, in, ptr->value.m);
  3075.           res = 1;
  3076.         }
  3077.     }
  3078.       sb_kill (&name);
  3079.     }
  3080.  
  3081.  
  3082.   return res;
  3083. }
  3084.  
  3085.  
  3086. /* STRING HANDLING */
  3087.  
  3088. static int
  3089. getstring (idx, in, acc)
  3090.      int idx;
  3091.      sb *in;
  3092.      sb *acc;
  3093. {
  3094.   idx = sb_skip_white (idx, in);
  3095.  
  3096.   while (idx < in->len
  3097.      && (in->ptr[idx] == '"' 
  3098.          || in->ptr[idx] == '<' 
  3099.          || (in->ptr[idx] == '\'' && alternate)))
  3100.     {
  3101.       if (in->ptr[idx] == '<')
  3102.     {
  3103.       if (alternate)
  3104.         {
  3105.           int nest = 0;
  3106.           idx++;
  3107.           while ((in->ptr[idx] != '>' || nest)
  3108.              && idx < in->len)
  3109.         {
  3110.           if (in->ptr[idx] == '!')
  3111.             {
  3112.               idx++  ;
  3113.               sb_add_char (acc, in->ptr[idx++]);
  3114.             }
  3115.           else {
  3116.             if (in->ptr[idx] == '>')
  3117.               nest--;
  3118.             if (in->ptr[idx] == '<')
  3119.               nest++;
  3120.             sb_add_char (acc, in->ptr[idx++]);
  3121.           }
  3122.         }
  3123.           idx++;
  3124.         }
  3125.       else {
  3126.         int code;
  3127.         idx++;
  3128.         idx = exp_get_abs ("Character code in string must be absolute expression.\n",
  3129.                    idx, in, &code);
  3130.         sb_add_char (acc, code);
  3131.  
  3132.         if (in->ptr[idx] != '>')
  3133.           ERROR ((stderr, "Missing > for character code.\n"));
  3134.         idx++;
  3135.       }
  3136.     }
  3137.       else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
  3138.     {
  3139.       char tchar = in->ptr[idx];
  3140.       idx++;
  3141.       while (idx < in->len)
  3142.         {
  3143.           if (alternate && in->ptr[idx] == '!')
  3144.         {
  3145.           idx++  ;
  3146.           sb_add_char (acc, in->ptr[idx++]);
  3147.         }
  3148.           else {
  3149.         if (in->ptr[idx] == tchar)
  3150.           {
  3151.             idx++;
  3152.             if (idx >= in->len || in->ptr[idx] != tchar)
  3153.               break;
  3154.           }
  3155.         sb_add_char (acc, in->ptr[idx]);
  3156.         idx++;
  3157.           }
  3158.         }
  3159.     }
  3160.     }
  3161.   
  3162.   return idx;
  3163. }
  3164.  
  3165. /* .SDATA[C|Z] <string> */
  3166.  
  3167. static
  3168. void
  3169. do_sdata (idx, in, type)
  3170.      int idx;
  3171.      sb *in;
  3172.      char type;
  3173. {
  3174.   int nc = 0;
  3175.   int pidx = -1;
  3176.   sb acc;
  3177.   sb_new (&acc);
  3178.   fprintf (outfile, ".byte\t");
  3179.  
  3180.   while (!eol (idx, in))
  3181.     {
  3182.       int i;
  3183.       sb_reset (&acc);
  3184.       idx = sb_skip_white (idx, in);
  3185.       while (!eol (idx, in))
  3186.     {
  3187.       pidx = idx = get_any_string (idx, in, &acc, 0, 1);
  3188.       if (type == 'c')
  3189.         {
  3190.           if (acc.len > 255)
  3191.         {
  3192.           ERROR ((stderr, "string for SDATAC longer than 255 characters (%d).\n", acc.len));
  3193.         }
  3194.           fprintf (outfile, "%d", acc.len);
  3195.           nc = 1;
  3196.         }
  3197.  
  3198.       for (i = 0; i < acc.len; i++)
  3199.         {
  3200.           if (nc)
  3201.         {
  3202.           fprintf (outfile, ",");
  3203.         }
  3204.           fprintf (outfile, "%d", acc.ptr[i]);
  3205.           nc = 1;
  3206.         }
  3207.  
  3208.       if (type == 'z')
  3209.         {
  3210.           if (nc)
  3211.         fprintf (outfile, ",");
  3212.           fprintf (outfile, "0");
  3213.         }
  3214.       idx = sb_skip_comma (idx, in);
  3215.       if (idx == pidx) break;
  3216.     }
  3217.       if (!alternate && in->ptr[idx] != ',' && idx != in->len)
  3218.     {
  3219.       fprintf (outfile, "\n");
  3220.       ERROR ((stderr, "illegal character in SDATA line (0x%x).\n", in->ptr[idx]));
  3221.       break;
  3222.     }
  3223.       idx++;
  3224.     }
  3225.   sb_kill (&acc);
  3226.   fprintf (outfile, "\n");
  3227. }
  3228.  
  3229. /* .SDATAB <count> <string> */
  3230.  
  3231. static void
  3232. do_sdatab (idx, in)
  3233.      int idx;
  3234.      sb *in;
  3235. {
  3236.   int repeat;
  3237.   int i;
  3238.   sb acc;
  3239.   sb_new (&acc);
  3240.  
  3241.   idx = exp_get_abs ("Must have absolute SDATAB repeat count.\n", idx, in, &repeat);
  3242.   if (repeat <= 0)
  3243.     {
  3244.       ERROR ((stderr, "Must have positive SDATAB repeat count (%d).\n", repeat));
  3245.       repeat = 1;
  3246.     }
  3247.  
  3248.   idx = sb_skip_comma (idx, in);
  3249.   idx = getstring (idx, in, &acc);
  3250.  
  3251.   for (i = 0; i < repeat; i++)
  3252.     {
  3253.       if (i)
  3254.     fprintf (outfile, "\t");
  3255.       fprintf (outfile, ".byte\t");
  3256.       sb_print (&acc);
  3257.       fprintf (outfile, "\n");
  3258.     }
  3259.   sb_kill (&acc);
  3260.  
  3261. }
  3262.  
  3263. int
  3264. new_file (name)
  3265.      char *name;
  3266. {
  3267.   FILE *newone = fopen (name, "r");
  3268.   if (!newone)
  3269.     return 0;
  3270.  
  3271.   if (isp == MAX_INCLUDES)
  3272.     FATAL ((stderr, "Unreasonable include depth (%ld).\n", (long) isp));
  3273.  
  3274.   sp++;
  3275.   sp->handle = newone;
  3276.  
  3277.   sb_new (&sp->name);
  3278.   sb_add_string (&sp->name, name);
  3279.  
  3280.   sp->linecount = 1;
  3281.   sp->pushback_index = 0;
  3282.   sp->type = include_file;
  3283.   sp->index = 0;
  3284.   sb_new (&sp->pushback);
  3285.   return 1;
  3286. }
  3287.  
  3288. static void
  3289. do_include (idx, in)
  3290.      int idx;
  3291.      sb *in;
  3292. {
  3293.   sb t;
  3294.   char *text;
  3295.   sb_new (&t);
  3296.   idx = getstring (idx, in, &t);
  3297.   text = sb_name (&t);
  3298.   if (!new_file (text))
  3299.     {
  3300.       FATAL ((stderr, "Can't open include file `%s'.\n", text));
  3301.     }
  3302.   sb_kill (&t);
  3303. }
  3304.  
  3305. static void
  3306. include_pop ()
  3307. {
  3308.   if (sp != include_stack)
  3309.     {
  3310.       if (sp->handle)
  3311.     fclose (sp->handle);
  3312.       sp--;
  3313.     }
  3314. }
  3315.  
  3316. /* Get the next character from the include stack.  If there's anything
  3317.    in the pushback buffer, take that first.  If we're at eof, pop from
  3318.    the stack and try again.  Keep the linecount up to date. */
  3319.  
  3320. static int
  3321. get ()
  3322. {
  3323.   int r;
  3324.  
  3325.   if (sp->pushback.len != sp->pushback_index)
  3326.     {
  3327.       r = (char) (sp->pushback.ptr[sp->pushback_index++]);
  3328.       /* When they've all gone, reset the pointer */
  3329.       if (sp->pushback_index == sp->pushback.len)
  3330.     {
  3331.       sp->pushback.len = 0;
  3332.       sp->pushback_index = 0;
  3333.     }
  3334.     }
  3335.   else if (sp->handle)
  3336.     {
  3337.       r = getc (sp->handle);
  3338.     }
  3339.   else
  3340.     r = EOF;
  3341.  
  3342.   if (r == EOF && isp)
  3343.     {
  3344.       include_pop ();
  3345.       r = get ();
  3346.       while (r == EOF && isp)
  3347.     {
  3348.       include_pop ();
  3349.       r = get ();
  3350.     }
  3351.       return r;
  3352.     }
  3353.   if (r == '\n')
  3354.     {
  3355.       sp->linecount++;
  3356.     }
  3357.  
  3358.   return r;
  3359. }
  3360.  
  3361. static int
  3362. linecount ()
  3363. {
  3364.   return sp->linecount;
  3365. }
  3366.  
  3367. static int
  3368. include_next_index ()
  3369. {
  3370.   static int index;
  3371.   if (!unreasonable
  3372.       && index > MAX_REASONABLE)
  3373.     FATAL ((stderr, "Unreasonable expansion (-u turns off check).\n"));
  3374.   return ++index;
  3375. }
  3376.  
  3377.  
  3378. /* Initialize the chartype vector. */
  3379.  
  3380. static void
  3381. chartype_init ()
  3382. {
  3383.   int x;
  3384.   for (x = 0; x < 256; x++)
  3385.     {
  3386.       if (isalpha (x) || x == '_' || x == '$')
  3387.     chartype[x] |= FIRSTBIT;
  3388.  
  3389.       if (isdigit (x) || isalpha (x) || x == '_' || x == '$')
  3390.     chartype[x] |= NEXTBIT;
  3391.  
  3392.       if (x == ' ' || x == '\t' || x == ',' || x == '"' || x == ';'
  3393.       || x == '"' || x == '<' || x == '>' || x == ')' || x == '(')
  3394.     chartype[x] |= SEPBIT;
  3395.  
  3396.       if (x == 'b' || x == 'B'
  3397.       || x == 'q' || x == 'Q'
  3398.       || x == 'h' || x == 'H'
  3399.       || x == 'd' || x == 'D')
  3400.     chartype [x] |= BASEBIT;
  3401.       
  3402.       if (x == ' ' || x == '\t')
  3403.     chartype[x] |= WHITEBIT;
  3404.  
  3405.       if (x == comment_char)
  3406.     chartype[x] |= COMMENTBIT;
  3407.     }
  3408. }
  3409.  
  3410.  
  3411.  
  3412. /* What to do with all the keywords */
  3413. #define PROCESS     0x1000  /* Run substitution over the line */
  3414. #define LAB        0x2000  /* Spit out the label */
  3415.  
  3416. #define K_EQU         PROCESS|1
  3417. #define K_ASSIGN     PROCESS|2
  3418. #define K_REG         PROCESS|3
  3419. #define K_ORG         PROCESS|4
  3420. #define K_RADIX     PROCESS|5
  3421. #define K_DATA         LAB|PROCESS|6
  3422. #define K_DATAB     LAB|PROCESS|7
  3423. #define K_SDATA     LAB|PROCESS|8
  3424. #define K_SDATAB     LAB|PROCESS|9
  3425. #define K_SDATAC     LAB|PROCESS|10
  3426. #define K_SDATAZ    LAB|PROCESS|11
  3427. #define K_RES         LAB|PROCESS|12
  3428. #define K_SRES         LAB|PROCESS|13
  3429. #define K_SRESC     LAB|PROCESS|14
  3430. #define K_SRESZ     LAB|PROCESS|15
  3431. #define K_EXPORT     LAB|PROCESS|16
  3432. #define K_GLOBAL     LAB|PROCESS|17
  3433. #define K_PRINT     LAB|PROCESS|19
  3434. #define K_FORM         LAB|PROCESS|20
  3435. #define K_HEADING    LAB|PROCESS|21
  3436. #define K_PAGE        LAB|PROCESS|22
  3437. #define K_IMPORT    LAB|PROCESS|23
  3438. #define K_PROGRAM    LAB|PROCESS|24
  3439. #define K_END        PROCESS|25
  3440. #define K_INCLUDE    PROCESS|26
  3441. #define K_IGNORED    PROCESS|27
  3442. #define K_ASSIGNA    PROCESS|28
  3443. #define K_ASSIGNC    29
  3444. #define K_AIF        PROCESS|30
  3445. #define K_AELSE        PROCESS|31
  3446. #define K_AENDI        PROCESS|32
  3447. #define K_AREPEAT    PROCESS|33
  3448. #define K_AENDR        PROCESS|34
  3449. #define K_AWHILE    35
  3450. #define K_AENDW        PROCESS|36
  3451. #define K_EXITM        37
  3452. #define K_MACRO        PROCESS|38
  3453. #define K_ENDM        39
  3454. #define K_ALIGN        PROCESS|LAB|40
  3455. #define K_ALTERNATE     41
  3456. #define K_DB        LAB|PROCESS|42
  3457. #define K_DW        LAB|PROCESS|43
  3458. #define K_DL        LAB|PROCESS|44
  3459. #define K_LOCAL        45
  3460.  
  3461.  
  3462. static struct
  3463. {
  3464.   char *name;
  3465.   int code;
  3466.   int extra;
  3467. }
  3468. kinfo[] =
  3469. {
  3470.   { "EQU", K_EQU, 0 },
  3471.   { "ALTERNATE", K_ALTERNATE, 0 },
  3472.   { "ASSIGN", K_ASSIGN, 0 },
  3473.   { "REG", K_REG, 0 },
  3474.   { "ORG", K_ORG, 0 },
  3475.   { "RADIX", K_RADIX, 0 },
  3476.   { "DATA", K_DATA, 0 },
  3477.   { "DB", K_DB, 0 },
  3478.   { "DW", K_DW, 0 },
  3479.   { "DL", K_DL, 0 },
  3480.   { "DATAB", K_DATAB, 0 },
  3481.   { "SDATA", K_SDATA, 0 },
  3482.   { "SDATAB", K_SDATAB, 0 },
  3483.   { "SDATAZ", K_SDATAZ, 0 },
  3484.   { "SDATAC", K_SDATAC, 0 },
  3485.   { "RES", K_RES, 0 },
  3486.   { "SRES", K_SRES, 0 },
  3487.   { "SRESC", K_SRESC, 0 },
  3488.   { "SRESZ", K_SRESZ, 0 },
  3489.   { "EXPORT", K_EXPORT, 0 },
  3490.   { "GLOBAL", K_GLOBAL, 0 },
  3491.   { "PRINT", K_PRINT, 0 },
  3492.   { "FORM", K_FORM, 0 },
  3493.   { "HEADING", K_HEADING, 0 },
  3494.   { "PAGE", K_PAGE, 0 },
  3495.   { "PROGRAM", K_IGNORED, 0 },
  3496.   { "END", K_END, 0 },
  3497.   { "INCLUDE", K_INCLUDE, 0 },
  3498.   { "ASSIGNA", K_ASSIGNA, 0 },
  3499.   { "ASSIGNC", K_ASSIGNC, 0 },
  3500.   { "AIF", K_AIF, 0 },
  3501.   { "AELSE", K_AELSE, 0 },
  3502.   { "AENDI", K_AENDI, 0 },
  3503.   { "AREPEAT", K_AREPEAT, 0 },
  3504.   { "AENDR", K_AENDR, 0 },
  3505.   { "EXITM", K_EXITM, 0 },
  3506.   { "MACRO", K_MACRO, 0 },
  3507.   { "ENDM", K_ENDM, 0 },
  3508.   { "AWHILE", K_AWHILE, 0 },
  3509.   { "ALIGN", K_ALIGN, 0 },
  3510.   { "AENDW", K_AENDW, 0 },
  3511.   { "ALTERNATE", K_ALTERNATE, 0 },
  3512.   { "LOCAL", K_LOCAL, 0 },
  3513.   { NULL, 0, 0 }
  3514. };
  3515.  
  3516. /* Look for a pseudo op on the line. If one's there then call
  3517.    its handler. */
  3518.  
  3519. static int
  3520. process_pseudo_op (idx, line, acc)
  3521.      int idx;
  3522.      sb *line;
  3523.      sb *acc;
  3524. {
  3525.  
  3526.  
  3527.   if (line->ptr[idx] == '.' || alternate)
  3528.     {
  3529.       /* Scan forward and find pseudo name */
  3530.       char *in;
  3531.       hash_entry *ptr;
  3532.  
  3533.       char *s;
  3534.       char *e;
  3535.       if (line->ptr[idx] == '.')
  3536.     idx++;
  3537.       in = line->ptr + idx;
  3538.       s = in;
  3539.       e = s;
  3540.       sb_reset (acc);
  3541.  
  3542.       while (idx < line->len && *e && ISFIRSTCHAR (*e))
  3543.     {
  3544.       sb_add_char (acc, *e);
  3545.       e++;
  3546.       idx++;
  3547.     }
  3548.  
  3549.       ptr = hash_lookup (&keyword_hash_table, acc);
  3550.  
  3551.       if (!ptr)
  3552.     {
  3553. #if 0
  3554.       /* This one causes lots of pain when trying to preprocess
  3555.          ordinary code */
  3556.       WARNING ((stderr, "Unrecognised pseudo op `%s'.\n", sb_name (acc)));
  3557. #endif
  3558.       return 0;
  3559.     }
  3560.       if (ptr->value.i & LAB)
  3561.     {            /* output the label */
  3562.       if (label.len)
  3563.         {
  3564.           fprintf (outfile, "%s:\t", sb_name (&label));
  3565.         }
  3566.       else
  3567.         fprintf (outfile, "\t");
  3568.     }
  3569.  
  3570.       if (ptr->value.i & PROCESS)
  3571.     {
  3572.       /* Polish the rest of the line before handling the pseudo op */
  3573. #if 0
  3574.       strip_comments(line);
  3575. #endif
  3576.       sb_reset (acc);
  3577.       process_assigns (idx, line, acc);
  3578.       sb_reset(line);
  3579.       change_base (0, acc, line);
  3580.       idx = 0;
  3581.     }
  3582.       if (!condass_on ())
  3583.     {
  3584.       switch (ptr->value.i)
  3585.         {
  3586.         case K_AIF:
  3587.           do_aif (idx, line);
  3588.           break;
  3589.         case K_AELSE:
  3590.           do_aelse ();
  3591.           break;
  3592.         case K_AENDI:
  3593.           do_aendi ();
  3594.           break;
  3595.         }
  3596.       return 1;
  3597.     }
  3598.       else
  3599.     {
  3600.       switch (ptr->value.i)
  3601.         {
  3602.         case K_ALTERNATE:
  3603.           alternate = 1;
  3604.           return 1;
  3605.         case K_AELSE:
  3606.           do_aelse ();
  3607.           return 1;
  3608.         case K_AENDI:
  3609.           do_aendi ();
  3610.           return 1;
  3611.         case K_ORG:
  3612.           ERROR ((stderr, "ORG command not allowed.\n"));
  3613.           break;
  3614.         case K_RADIX:
  3615.           do_radix (line);
  3616.           return 1;
  3617.         case K_DB:
  3618.           do_data (idx, line, 1);
  3619.           return 1;
  3620.         case K_DW:
  3621.           do_data (idx, line, 2);
  3622.           return 1;
  3623.         case K_DL:
  3624.           do_data (idx, line, 4);
  3625.           return 1;
  3626.         case K_DATA:
  3627.           do_data (idx, line, 0);
  3628.           return 1;
  3629.         case K_DATAB:
  3630.           do_datab (idx, line);
  3631.           return 1;
  3632.         case K_SDATA:
  3633.           do_sdata (idx, line, 0);
  3634.           return 1;
  3635.         case K_SDATAB:
  3636.           do_sdatab (idx, line);
  3637.           return 1;
  3638.         case K_SDATAC:
  3639.           do_sdata (idx, line, 'c');
  3640.           return 1;
  3641.         case K_SDATAZ:
  3642.           do_sdata (idx, line, 'z');
  3643.           return 1;
  3644.         case K_ASSIGN:
  3645.           do_assign (1, 0, line);
  3646.           return 1;
  3647.         case K_AIF:
  3648.           do_aif (idx, line);
  3649.           return 1;
  3650.         case K_AREPEAT:
  3651.           do_arepeat (idx, line);
  3652.           return 1;
  3653.         case K_AENDW:
  3654.           do_aendw ();
  3655.           return 1;
  3656.         case K_AWHILE:
  3657.           do_awhile (idx, line);
  3658.           return 1;
  3659.         case K_AENDR:
  3660.           do_aendr ();
  3661.           return 1;
  3662.         case K_EQU:
  3663.           do_assign (0, idx, line);
  3664.           return 1;
  3665.         case K_ALIGN:
  3666.           do_align (idx, line);
  3667.           return 1;
  3668.         case K_RES:
  3669.           do_res (idx, line, 0);
  3670.           return 1;
  3671.         case K_SRES:
  3672.           do_res (idx, line, 's');
  3673.           return 1;
  3674.         case K_INCLUDE:
  3675.           do_include (idx, line);
  3676.           return 1;
  3677.         case K_LOCAL:
  3678.           do_local (idx, line);
  3679.           return 1;
  3680.         case K_MACRO:
  3681.           do_macro (idx, line);
  3682.           return 1;
  3683.         case K_ENDM:
  3684.           do_endm ();
  3685.           return 1;
  3686.         case K_SRESC:
  3687.           do_res (idx, line, 'c');
  3688.           return 1;
  3689.         case K_PRINT:
  3690.           do_print (idx, line);
  3691.           return 1;
  3692.         case K_FORM:
  3693.           do_form (idx, line);
  3694.           return 1;
  3695.         case K_HEADING:
  3696.           do_heading (idx, line);
  3697.           return 1;
  3698.         case K_PAGE:
  3699.           do_page ();
  3700.           return 1;
  3701.         case K_GLOBAL:
  3702.         case K_EXPORT:
  3703.           do_export (line);
  3704.           return 1;
  3705.         case K_IMPORT:
  3706.           return 1;
  3707.         case K_SRESZ:
  3708.           do_res (idx, line, 'z');
  3709.           return 1;
  3710.         case K_IGNORED:
  3711.           return 1;
  3712.         case K_END:
  3713.           do_end ();
  3714.           return 1;
  3715.         case K_ASSIGNA:
  3716.           do_assigna (idx, line);
  3717.           return 1;
  3718.         case K_ASSIGNC:
  3719.           do_assignc (idx, line);
  3720.           return 1;
  3721.         case K_EXITM:
  3722.           do_exitm ();
  3723.           return 1;
  3724.         case K_REG:
  3725.           do_reg (idx, line);
  3726.           return 1;
  3727.         }
  3728.     }
  3729.     }
  3730.   return 0;
  3731. }
  3732.  
  3733.  
  3734.  
  3735. /* Build the keyword hash table - put each keyword in the table twice,
  3736.    once upper and once lower case.*/
  3737.  
  3738. static void
  3739. process_init ()
  3740. {
  3741.   int i;
  3742.  
  3743.   for (i = 0; kinfo[i].name; i++)
  3744.     {
  3745.       sb label;
  3746.       int j;
  3747.       sb_new (&label);
  3748.       sb_add_string (&label, kinfo[i].name);
  3749.  
  3750.       hash_add_to_int_table (&keyword_hash_table, &label, kinfo[i].code);
  3751.  
  3752.       sb_reset (&label);
  3753.       for (j = 0; kinfo[i].name[j]; j++)
  3754.     sb_add_char (&label, kinfo[i].name[j] - 'A' + 'a');
  3755.       hash_add_to_int_table (&keyword_hash_table, &label, kinfo[i].code);
  3756.  
  3757.       sb_kill (&label);
  3758.     }
  3759. }
  3760.  
  3761.  
  3762. static void
  3763. do_define (string)
  3764. char *string;
  3765. {
  3766.   sb label;
  3767.   int res = 1;
  3768.   hash_entry *ptr;
  3769.   sb_new (&label);
  3770.  
  3771.  
  3772.   while (*string)
  3773.     {
  3774.       if (*string == '=') 
  3775.     {
  3776.       sb value;
  3777.       sb_new (&value);
  3778.       string++;
  3779.       while (*string)
  3780.         {
  3781.           sb_add_char (&value, *string);
  3782.           string++;
  3783.         }
  3784.       exp_get_abs ("Invalid expression on command line.\n", 0, &value, &res);
  3785.       sb_kill (&value);
  3786.       break;
  3787.     }
  3788.       sb_add_char (&label, *string);
  3789.  
  3790.       string ++;
  3791.     }
  3792.  
  3793.   ptr = hash_create (&vars, &label);
  3794.   free_old_entry (ptr);
  3795.   ptr->type = hash_integer;
  3796.   ptr->value.i = res;
  3797.   sb_kill (&label);
  3798. }
  3799. char *program_name;
  3800.  
  3801. /* The list of long options.  */
  3802. static struct option long_options[] =
  3803. {
  3804.   { "alternate", no_argument, 0, 'a' },
  3805.   { "commentchar", required_argument, 0, 'c' },
  3806.   { "copysource", no_argument, 0, 's' },
  3807.   { "debug", no_argument, 0, 'd' },
  3808.   { "help", no_argument, 0, 'h' },
  3809.   { "output", required_argument, 0, 'o' },
  3810.   { "print", no_argument, 0, 'p' },
  3811.   { "unreasonable", no_argument, 0, 'u' },
  3812.   { "version", no_argument, 0, 'v' },
  3813.   { "define", required_argument, 0, 'd' },
  3814.   { NULL, no_argument, 0, 0 }
  3815. };
  3816.  
  3817. /* Show a usage message and exit.  */
  3818. static void
  3819. show_usage (file, status)
  3820.      FILE *file;
  3821.      int status;
  3822. {
  3823.   fprintf (file, "\
  3824. Usage: %s \n\
  3825.   [-a]      [--alternate]         enter alternate macro mode\n\
  3826.   [-c char] [--commentchar char]  change the comment character from !\n\
  3827.   [-d]      [--debug]             print some debugging info\n\
  3828.   [-h]      [--help]              print this message\n\
  3829.   [-o out]  [--output out]        set the output file\n\
  3830.   [-p]      [--print]             print line numbers\n\
  3831.   [-s]      [--copysource]        copy source through as comments \n\
  3832.   [-u]      [--unreasonable]      allow unreasonable nesting\n\
  3833.   [-v]      [--version]           print the program version\n\
  3834.   [-Dname=value]                  create preprocessor variable called name, with value\n\
  3835.   [in-file]\n",   program_name);
  3836.   exit (status);
  3837. }
  3838.  
  3839. /* Display a help message and exit.  */
  3840. static void
  3841. show_help ()
  3842. {
  3843.   printf ("%s: Gnu Assembler Macro Preprocessor\n",
  3844.       program_name);
  3845.   show_usage (stdout, 0);
  3846. }
  3847.  
  3848. int
  3849. main (argc, argv)
  3850.      int argc;
  3851.      char **argv;
  3852. {
  3853.   int opt;
  3854.   char *out_name = 0;
  3855.   sp = include_stack;
  3856.  
  3857.   ifstack[0].on = 1;
  3858.   ifi = 0;
  3859.  
  3860.  
  3861.  
  3862.   program_name = argv[0];
  3863.   xmalloc_set_program_name (program_name);
  3864.  
  3865.   hash_new_table (101, ¯o_table);
  3866.   hash_new_table (101, &keyword_hash_table);
  3867.   hash_new_table (101, &assign_hash_table);
  3868.   hash_new_table (101, &vars);
  3869.  
  3870.   sb_new (&label);
  3871.   process_init ();
  3872.  
  3873.   while ((opt = getopt_long (argc, argv, "sdhavc:upo:D:", long_options,
  3874.                  (int *) NULL))
  3875.      != EOF)
  3876.     {
  3877.       switch (opt)
  3878.     {
  3879.     case 'o':
  3880.       out_name = optarg;
  3881.       break;
  3882.     case 'u':
  3883.       unreasonable = 1;
  3884.       break;
  3885.     case 'p':
  3886.       print_line_number = 1;
  3887.       break;
  3888.     case 'c':
  3889.       comment_char = optarg[0];
  3890.       break;
  3891.     case 'a':
  3892.       alternate = 1;
  3893.       break;
  3894.     case 's':
  3895.       copysource = 1;
  3896.       break;
  3897.     case 'd':
  3898.       stats = 1;
  3899.       break;
  3900.     case 'D':
  3901.       do_define (optarg);
  3902.       break;
  3903.     case 'h':
  3904.       show_help ();
  3905.       /*NOTREACHED*/
  3906.     case 'v':
  3907.       printf ("GNU %s version %s\n", program_name, program_version);
  3908.       exit (0);
  3909.       /*NOTREACHED*/
  3910.     case 0:
  3911.       break;
  3912.     default:
  3913.       show_usage (stderr, 1);
  3914.       /*NOTREACHED*/
  3915.     }
  3916.     }
  3917.  
  3918.  
  3919.   if (out_name) {
  3920.     outfile = fopen (out_name, "w");
  3921.     if (!outfile)
  3922.       {
  3923.     fprintf (stderr, "%s: Can't open output file `%s'.\n",
  3924.          program_name, out_name);
  3925.     exit (1);
  3926.       }
  3927.   }
  3928.   else  {
  3929.     outfile = stdout;
  3930.   }
  3931.  
  3932.   chartype_init ();
  3933.   if (!outfile)
  3934.     outfile = stdout;
  3935.  
  3936.   /* Process all the input files */
  3937.  
  3938.   while (optind < argc)
  3939.     {
  3940.       if (new_file (argv[optind]))
  3941.     {
  3942.       process_file ();
  3943.     }
  3944.       else
  3945.     {
  3946.       fprintf (stderr, "%s: Can't open input file `%s'.\n",
  3947.            program_name, argv[optind]);
  3948.       exit (1);
  3949.     }
  3950.       optind++;
  3951.     }
  3952.  
  3953.   quit ();
  3954.   return 0;
  3955. }
  3956.